如果类成员typedef不存在,则使用默认类型的模板专门化 [英] Template specialization to use default type if class member typedef does not exist

查看:130
本文介绍了如果类成员typedef不存在,则使用默认类型的模板专门化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写使用模板参数的成员typedef的代码,但如果模板参数没有typedef,则需要提供默认类型。我试过的一个简单的例子是:

I'm trying to write code that uses a member typedef of a template argument, but want to supply a default type if the template argument does not have that typedef. A simplified example I've tried is this:

struct DefaultType    { DefaultType()    { printf("Default ");    } };
struct NonDefaultType { NonDefaultType() { printf("NonDefault "); } };

struct A {};
struct B { typedef NonDefaultType Type; };

template<typename T, typename Enable = void> struct Get_Type { 
    typedef DefaultType Type; 
};
template<typename T> struct Get_Type< T, typename T::Type > {
    typedef typename T::Type  Type; 
};

int main()
{
    Get_Type<A>::Type test1;
    Get_Type<B>::Type test2;
}



我希望这将打印默认非默认,而是打印默认默认值。我的期望是,main()中的第二行应该匹配Get_Type的专门版本,因为B :: Type存在。

I would expect this to print "Default NonDefault", but instead it prints "Default Default". My expectation is that the second line in main() should match the specialized version of Get_Type, because B::Type exists. However, this does not happen.

任何人都可以解释这里发生了什么以及如何解决这个问题,或以其他方式达成同样的目标?

Can anyone explain what's going on here and how to fix it, or another way to accomplish the same goal?

谢谢。

编辑:

Georg提供了另一种方法,但我仍然很好奇为什么这不工作。根据boost enable_if文档,一种专门用于不同类型的模板的方式是这样的:

Georg gave an alternate method, but I'm still curious about why this doesn't work. According the the boost enable_if docs, a way to specialize a template for different types is like so:

template <class T, class Enable = void> 
class A { ... };

template <class T>
class A<T, typename enable_if<is_integral<T> >::type> { ... };

template <class T>
class A<T, typename enable_if<is_float<T> >::type> { ... };

这是因为enable_if< true>具有类型typedef,但enable_if< false>不会。

This works because enable_if< true > has type as a typedef, but enable_if< false > does not.

我不明白这和我的版本有什么不同,其中,而不是使用enable_if我只是直接使用T :: Type。如果T :: Type存在不会与enable_if相同, true> :: type在上面的例子,并导致专业化被选择?并且如果T :: Type不存在,则不会与enable_if< false> :: type不存在并导致在上面的例子中选择默认版本?

I don't understand how this is different than my version, where instead of using enable_if I'm just using T::Type directly. If T::Type exists wouldn't that be the same as enable_if< true >::type in the above example and cause the specialization to be chosen? And if T::Type doesn't exist, wouldn't that be the same as enable_if< false >::type not existing and causing the default version to be chosen in the above example?

推荐答案

你的specialization参数传递成员typedef,并期望它产生 void 作为类型。这里没有什么魔术 - 它只是使用默认参数。让我们看看它是如何工作的。如果你说 Get_Type< Foo> :: type ,编译器使用默认参数启用 c $ c> void ,类型名称变为 Get_Type< Foo,void> :: type 。现在,编译器检查是否有任何部分特化匹配。

To answer your addition - your specialization argument passes the member typedef and expects it to yield void as type. There is nothing magic about this - it just uses a default argument. Let's see how it works. If you say Get_Type<Foo>::type, the compiler uses the default argument of Enable, which is void, and the type name becomes Get_Type<Foo, void>::type. Now, the compiler checks whether any partial specialization matches.

您的部分专业化参数列表< T,typename T :: Type> 是从原始参数列表< Foo,void> 。这将推导 T Foo ,然后替换 Foo 到特殊化的第二个参数中,为您的部分特化生成< Foo,NonDefaultType> 的最终结果。然而,这不符合原始的参数列表< Foo,void>

Your partial specialization's argument list <T, typename T::Type> is deduced from the original argument list <Foo, void>. This will deduce T to Foo and afterwards substitutes that Foo into the second argument of the specialization, yielding a final result of <Foo, NonDefaultType> for your partial specialization. That doesn't, however, match the original argument list <Foo, void> at all!

需要一种方法来生成 void 类型,如下所示:

You need a way to yield the void type, as in the following:

template<typename T>
struct tovoid { typedef void type; };

template<typename T, typename Enable = void> struct Get_Type { 
    typedef DefaultType Type; 
};
template<typename T> 
struct Get_Type< T, typename tovoid<typename T::Type>::type > {
    typedef typename T::Type  Type; 
};

现在这将像你所期望的那样工作。使用MPL,您可以使用总是而不是 tovoid

Now this will work like you expect. Using MPL, you can use always instead of tovoid

typename apply< always<void>, typename T::type >::type

这篇关于如果类成员typedef不存在,则使用默认类型的模板专门化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆