为什么功能模板不能部分专业化?


87

我知道语言规范禁止 对功能模板进行部分专业化。

我想知道为什么它禁止这样做的理由?它们没有用吗?

template<typename T, typename U> void f() {}   //allowed!
template<> void f<int, char>()            {}   //allowed!
template<typename T> void f<char, T>()    {}   //not allowed!
template<typename T> void f<T, int>()     {}   //not allowed!

对于template<typename T, typename U> void f(T t, U u) {}同样 template<> void f(int t, char u) {}是允许的。
破事2016年

10
我发现有趣的是,当问题不是“我如何实现类似的目标”而是“此行为的背后原理是什么”时,人们会继续提供解决方法...我自己不知道选择这种方法的原因,但我认为委员会必须有理由禁止功能模板部分专业化。到目前为止,“最接近”的解释是Georgy发布的链接,该链接仅指出存在重载时功能模板部分专业化的潜在“风险”。但是,我不认为这是禁止使用此功能的原因,所以我认为还有更多功能
。– bartgol

Answers:


59

在C ++ 0x中已更改的AFAIK。

我想这只是一个疏忽(考虑到通过将函数放置为static类的成员,您总是可以使用更详细的代码来获得部分专业化效果)。

您可能会查找相关的DR(缺陷报告)(如果有)。

编辑:检查这一点,我发现其他人也相信这一点,但是没有人能够在标准草案中找到任何这样的支持。该SO线程似乎表明C ++ 0x不支持功能模板的部分专业化

编辑2:只是我的意思是“将函数作为static类的成员放置”的一个示例:

#include <iostream>
using namespace std;

// template<typename T, typename U> void f() {}   //allowed!
// template<> void f<int, char>()            {}   //allowed!
// template<typename T> void f<char, T>()    {}   //not allowed!
// template<typename T> void f<T, int>()     {}   //not allowed!

void say( char const s[] ) { std::cout << s << std::endl; }

namespace detail {
    template< class T, class U >
    struct F {
        static void impl() { say( "1. primary template" ); }
    };

    template<>
    struct F<int, char> {
        static void impl() { say( "2. <int, char> explicit specialization" ); }
    };

    template< class T >
    struct F< char, T > {
        static void impl() { say( "3. <char, T> partial specialization" ); }
    };

    template< class T >
    struct F< T, int > {
        static void impl() { say( "4. <T, int> partial specialization" ); }
    };
}  // namespace detail

template< class T, class U >
void f() { detail::F<T, U>::impl(); }    

int main() {
    f<char const*, double>();       // 1
    f<int, char>();                 // 2
    f<char, double>();              // 3
    f<double, int>();               // 4
}

您在n3225中有标准吗?我进行了快速搜索,但找不到它:/
Matthieu M.

1
抱歉,一个字不见了。我有文档,但是找不到特定的段落。尽管提供了您的修改,但我想这仅仅是因为它不在其中:)
Matthieu M.

3
这在C ++ 0x中未更改。我也怀疑它的效用。您始终可以使模板超载并使用部分排序
Johannes Schaub-litb

1
较晚的更新:八年后即使在C ++ 17中也没有变化,并且似乎也没有进入C ++ 20。不过,看不到任何原因...
阿空加瓜

这是迄今为止最全面的执行理念,我相信
维克托

18

好吧,您确实不能执行部分函数/方法专门化,但是可以执行重载。

template <typename T, typename U>
T fun(U pObj){...}

// acts like partial specialization <T, int> AFAIK 
// (based on Modern C++ Design by Alexandrescu)
template <typename T>
T fun(int pObj){...} 

是这样,但我不知道它是否满足您。


1
哇,我的脑海里充满了模板,以至于我真的忘记了事情可能是多么简单:)
Johannes

1
不幸的是,当您在部分地对该函数进行专门化处理后想要传递可变参数时,情况并非如此。:(
Gwangmu Lee

我不确定传递可变参数模板意味着什么,所以我想知道它与部分专业化有何不同。您能否提供更多详细信息?
beginpluses

如果您只想为所有整数和浮点类型使用两个函数怎么办?
Dmitriy Dokshin


11

由于可以部分地专门化类,因此可以使用函子:

#include <iostream>

template < typename dtype , int k > struct fun
{
 int operator()()
 {
  return k ;
 }
} ;

template < typename dtype > struct fun < dtype , 0 >
{
 int operator()()
 {
  return 42 ;
 }
} ;

int main ( int argc , char * argv[] )
{
 std::cout << fun<float,5>()() << std::endl ;
 std::cout << fun<float,0>()() << std::endl ;
}

1
然后,您可以使用单个函数模板进行调用,从而摆脱丑陋的()()语法。
tmr232
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.