2011-04-13 148 views
1

这是对earlier question的续集问题(不同主题)。下面的代码结合Dehstil的建议使用专业化。模板模板参数的专业化

具有模板模板参数的函数应该如何专用?

下面的代码(其中两个专业化行不编译)使问题具体化。

#include <cassert> 

template<typename S> struct PA1 {}; 
template<typename S> struct PA2 {}; 
template<typename S> struct PB {}; 
template<typename S> struct PC {}; 

template<typename S> struct A1 { typedef PA1<S> P; }; 
template<typename S> struct A2 { typedef PA2<S> P; }; 
template<typename S> struct B { typedef PB <S> P; }; 
template<typename S> struct C { typedef PC <S> P; }; 

template<typename S, template<typename> class T> char fn(typename T<S>::P); 

template<typename S, template<typename> class T> char fn(typename T<S>::P) 
{ 
    return 'a'; 
} 

template<typename S> char fn<B<S> >(B<S>::P) { return 'b'; } 
template<typename S> char fn<C<S> >(C<S>::P) { return 'c'; } 

int main() 
{ 
    PA1<int> pa1; 
    PA2<int> pa2; 
    PB<int> pb; 
    PC<int> pc; 
    assert((fn<int, A1>(pa1)) == 'a'); 
    assert((fn<int, A2>(pa2)) == 'a'); 

    assert((fn<int, B>(pb)) == 'b'); 
    assert((fn<int, C>(pc)) == 'c'); 
} 

这四个功能重要的电话FN < ...,...>()调用时具有相同的特征,因为他们自己会驻留在适用于四类A1/A2模板类/公元前。

回答

3

函数模板的部分专用化不被C++标准允许!

重载您的功能,而不是专门化它们。由Herb萨特Template Specialization and Overloading


如何统一调用所有功能,如果你重载

由Herb萨特阅读解释,Why Not Specialize Function Templates?

然后阅读为什么超载比专业

撰写班级模板call并将其专门为:

template<class S, template<typename> class T> 
struct call 
{ 
    static char fn(typename T<S>::P &p) 
    { 
     return ::fn<S,T>(p); 
    } 
}; 

template<class S> 
struct call<S,B> 
{ 
    static char fn(typename B<S>::P &p) 
    { 
     return ::fn<S>(p); 
    } 
}; 

template<class S> 
struct call<S,C> 
{ 
    static char fn(typename C<S>::P &p) 
    { 
     return ::fn<S>(p); 
    } 
}; 

然后你就可以使用这个类模板调用所有功能统一为:

assert((call<int, A1>::fn(pa1)) == 'a'); 
assert((call<int, A2>::fn(pa2)) == 'a'); 

assert((call<int, B>::fn(pb)) == 'b'); 
assert((call<int, C>::fn(pc)) == 'c'); 

见在线演示:http://www.ideone.com/TISIT

注意在完整的解决方案,在同样的重载函数模板ideone.com(以上链接)

+0

签名变得不同,这就排除了在通用类中使用fn! – Calaf 2011-04-13 05:06:55

+0

@ user704972:过载可以具有相同的名称;实际上这就是超载的意思。 – Nawaz 2011-04-13 05:08:13

+0

我的意思是这个。假设我们现在有一个'template struct Foo {void g(...){... fn()...}};其中T可以是A1/A2/B/C中的任何一个。由于fn()仅以一种形式出现(例如,作为fn ()或fn()),其四种类型的定义也必须相同。 – Calaf 2011-04-13 05:16:29

1

函数只能完全专用。使用函数重载:

template<typename S> char fn(typename B<S>::P) { return 'b'; } 
template<typename S> char fn(typename C<S>::P) { return 'c'; } 
+0

一旦我使用重载,就不可能在泛型类中使用fn。与四种类型的fn的四次呼叫必须具有相同的签名。 – Calaf 2011-04-13 05:05:56

+0

@ user704972:此答案具有正确的语法;向我们展示“不可能使用'fn'”的情况。 – ildjarn 2011-04-13 05:22:22

+0

'template struct Action {Action(){}; char g(T :: P p){return fn(p); }};' – Calaf 2011-04-13 05:59:47