模板类内部函数的模板特化

发布于 2024-07-17 06:27:53 字数 591 浏览 11 评论 0原文

我有一个模板化类,里面有一个模板化函数(不同的模板参数),并且我在让编译器调用正确的函数时遇到问题。

示例:

template< class Parm1, class Parm2, class Parm3 >
class Class {
public:
   void   Func( Parm1 arg1, Parm2 arg2 ) {
      Call<Parm3>( arg1, arg2 ); 
   }

protected:
   template< class Type >
   void   Call( Parm1 arg1, Parm2 arg2 ) {
   }

   template<>
   void   Call<void>( Parm1 arg1, Parm2 arg2 ) {
   }
};

因此,如果 Parm3 的类型为“void”,我希望调用第二个 Call。 否则第一。 VS 工作正常,但 GCC 却很恶心。 它总是调用第一个。 现在这是一个非专业类专业化的问题,还是与我专业化“void”这一事实有关?

任何帮助都会很棒。 谢谢。

I have a templated class and inside I have a templated function( different template parameters ) and I having issues getting the compiler to call the correct one.

Example:

template< class Parm1, class Parm2, class Parm3 >
class Class {
public:
   void   Func( Parm1 arg1, Parm2 arg2 ) {
      Call<Parm3>( arg1, arg2 ); 
   }

protected:
   template< class Type >
   void   Call( Parm1 arg1, Parm2 arg2 ) {
   }

   template<>
   void   Call<void>( Parm1 arg1, Parm2 arg2 ) {
   }
};

So if the type of Parm3 is 'void' I want the second Call to be called. Otherwise the first. VS it works fine but GCC pukes all over it. It always calls the first one. Now is this an issue with specializing within of an unspecialized class or does it have something to do with the fact that Im specializing with 'void'

Any help would be great. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

雨的味道风的声音 2024-07-24 06:27:53

是的,在不完全专门化所有外部模板的情况下显式专门化函数是不可能的(显式函数专门化是一个真正的函数 - 它周围不能有任何仍由模板参数化的“可变部分”)

一种简单的方法是将 type2type 模板与重载结合使用:

template<typename T> struct t2t { typedef T type; };

void Func( Parm1 arg1, Parm2, arg2 ) { Call<Parm3>(arg1, arg2, t2t<Parm3>()); }
template< class Type, class V >  void Call( Parm1 arg1, Parm2 arg2, t2t<V>) { }
template< class Type >  void Call( Parm1 arg1, Parm2 arg2, t2t<void>) { }

现在,如果您使用 t2t 调用它,它将调用第二个 Call 重载,否则将调用第一个重载,因为第一个重载不太特别。

使用 enable_if 是可能的太:

void Func( Parm1 arg1, Parm2, arg2 ) { Call<Parm3>(arg1, arg2); }

template< class Type > typename disable_if< is_same<Type, void> >::type
Call( Parm1 arg1, Parm2 arg2) { }

template< class Type > typename enable_if< is_same<Type, void> >::type 
Call( Parm1 arg1, Parm2 arg2) { }

现在,如果 Type 为空,则采用第二个,如果 Type 再次为其他值,则采用第一个。 但使用不同的技术。 这个称为 SFINAE。 另一种方法,但再次添加一个参数是这样的 - 演示 SFINAE 的工作方式:

void Func( Parm1 arg1, Parm2, arg2 ) { Call<Parm3>(arg1, arg2); }

template< class Type >
void Call( Parm1 arg1, Parm2 arg2, char(*)[!is_same<Type, void>::value] = 0) { }

template< class Type > 
void Call( Parm1 arg1, Parm2 arg2, char(*)[ is_same<Type, void>::value] = 0) { }

如果模板参数的替换产生无效类型或构造,则会发生 SFINAE 。 下面,我们尝试创建一个分别指向大小为 0 或 1 的数组的指针。 大小为 0 的数组无效,并且会导致 SFINAE 失败 - 如果相应的模板特化是函数,则不会将其视为调用候选者。

在上面的 enable_if 情况下,它的工作方式有所不同。 如果 enable_if 被赋予从 false_type 派生的东西,那么它会使其 ::type typedef 不存在。 is_same 在类型不同的情况下派生自 false_type。 然后我们会尝试访问一个不存在的名称 - 这是一个无效的构造,因此也会导致 SFINAE 失败。

Yes, explicitly specializing a function without fully specializing all outer template is not possible (an explicit function specialization is a real function - there can't be any "variable parts" around it that are still parameterized by a template)

A simple way is to use a type2type template together with overloading:

template<typename T> struct t2t { typedef T type; };

void Func( Parm1 arg1, Parm2, arg2 ) { Call<Parm3>(arg1, arg2, t2t<Parm3>()); }
template< class Type, class V >  void Call( Parm1 arg1, Parm2 arg2, t2t<V>) { }
template< class Type >  void Call( Parm1 arg1, Parm2 arg2, t2t<void>) { }

Now, it will call the second Call overload if you call it with t2t<void>, and the first otherwise, because the first one is less special.

Using enable_if is possible too:

void Func( Parm1 arg1, Parm2, arg2 ) { Call<Parm3>(arg1, arg2); }

template< class Type > typename disable_if< is_same<Type, void> >::type
Call( Parm1 arg1, Parm2 arg2) { }

template< class Type > typename enable_if< is_same<Type, void> >::type 
Call( Parm1 arg1, Parm2 arg2) { }

Now, the second one is taken if Type is void, and the first one is taken if Type is something else again. But using a different technique. This one is called SFINAE. An alternative way, but which again adds one parameter is this - to demonstrate the way SFINAE works:

void Func( Parm1 arg1, Parm2, arg2 ) { Call<Parm3>(arg1, arg2); }

template< class Type >
void Call( Parm1 arg1, Parm2 arg2, char(*)[!is_same<Type, void>::value] = 0) { }

template< class Type > 
void Call( Parm1 arg1, Parm2 arg2, char(*)[ is_same<Type, void>::value] = 0) { }

SFINAE happens if the substitution of a template parameter yields to an invalid type or construct. Below, we try to create a pointer to an array of size 0 or 1 respectively. An array of size 0 is not valid, and will cause an SFINAE failure - the corresponding template specialization will not be considered as a call-candidate if it is a function.

In the enable_if case above, it works different. If enable_if is given something derived from false_type, then it makes its ::type typedef not existent. is_same derives itself from false_type in the case types are not the same. We would then try to access a not existent name - which is an invalid construct and would therefor be an SFINAE failure too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文