模板别名和专业化

时间:2016-07-24 19:09:17

标签: c++

假设我们有

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>::ContainerFoo是否会被视为同一个问题?那就是:

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,FooPack<Foo>::Container不是一回事,但是GCC disagrees,这很酷,因为这正是我想要的。

那么,谁是对的?

PS:我不确定我是否在标题上使用了正确的术语,也不在我的问题正文中。建议和更正非常受欢迎。

1 个答案:

答案 0 :(得分:1)

  

14.5.7 Alias templates

     

1模板声明,声明是别名声明      (第7条)将标识符声明为别名模板。别名      template是一个类型的名称。别名的名称      template是模板名称。

     

2当template-id引用别名的特化时      模板,它相当于获得的关联类型      将模板参数替换为模板参数      在别名模板的type-id中。

在您的示例FooPack<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>&) {}