如果类成员typedef不存在,则使用默认类型的模板专门化 [英] Template specialization to use default type if class member typedef does not exist
问题描述
我正在尝试编写使用模板参数的成员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屋!