假设我们有
template<typename T>
struct Foo
{
};
template<typename T>
struct Bar
{
};
template< template<typename T> class C >
struct Pack
{
template<typename T>
using Container = C<T>;
};
如果我们对Foo
进行专业化,那么Pack<Foo>::Container
和Foo
是否会被视为同一个问题?那就是:
template< template<typename T> class C >
struct IsFoo : std::false_type
{
};
template<>
struct IsFoo<Foo> : std::true_type
{
};
static_assert( IsFoo<Foo>::value, "Only foos!" );
static_assert( IsFoo< Pack<Foo>::Container >::value, "Only foos!" ); // ???
static_assert( IsFoo< Pack<Bar>::Container >::value == false, "Not a foo!" );
第二个断言是否正确?预期的行为是什么?哎呀,我正在努力做甚至有效吗?
我在三个编译器上测试过,得到了不同的结果。似乎是为了
MSVC和CLang,Foo
和Pack<Foo>::Container
不是一回事,但是GCC disagrees,这很酷,因为这正是我想要的。
那么,谁是对的?
PS:我不确定我是否在标题上使用了正确的术语,也不在我的问题正文中。建议和更正非常受欢迎。
答案 0 :(得分:1)
1模板声明,声明是别名声明 (第7条)将标识符声明为别名模板。别名 template是一个类型的名称。别名的名称 template是模板名称。
2当template-id引用别名的特化时 模板,它相当于获得的关联类型 将模板参数替换为模板参数 在别名模板的type-id中。
在您的示例Foo
和Pack<Foo>::Container
(无参数列表)中,模板名称不代表类型,只是模板。例如,Foo<int>
和Pack<Foo>::Container<int>
将是模板ID,因此是等效的。
据我所知,标准没有指定模板名称之间的任何等价关系,所以MSVC和Clang都认为只有相同的模板名称是等价的。
但如果对于您的特定用例来说足够了,您仍然可以根据模板ID进行专门化或重载。 e.g:
template< typename C >
struct IsFoo : std::false_type
{
};
template<class T>
struct IsFoo<Foo<T>> : std::true_type
{
};
static_assert( IsFoo<Foo<int>>::value, "Only foos!" );
static_assert( IsFoo< Pack<Foo>::Container<int> >::value, "Only foos!" );
static_assert( IsFoo< Pack<Bar>::Container<int> >::value == false, "Not a foo!" );
或
template<class T>
void do_stuff(const T&) {}
template<class T>
void do_stuff(const Foo<T>&) {}