请考虑以下代码:
#include <type_traits>
template<template<class...> class T, class... U>
struct is_specialization_of : std::false_type{};
template<template<class...> class T, class... U>
struct is_specialization_of<T, T<U...>> : std::true_type{};
template<class T, class U = int>
struct test{};
// (1) ok
static_assert(is_specialization_of<test, test<int>>::value, "1");
template<class T>
using alias = test<T>;
// (2) fails
static_assert(is_specialization_of<alias, alias<int>>::value, "2");
int main()
{
}
为什么(2),即使用别名模板的static_assert
会失败?
(2)中的模板参数推导过程与(1)中的有何不同?
这是CWG第1286期。 问题是:alias
和test
等价吗? [temp.type]中曾经有一个示例,它建议y
和z
在这里具有相同的类型:
template<template<class> class TT> struct X { };
template<class> struct Y { };
template<class T> using Z = Y<T>;
X<Y> y;
X<Z> z;
该示例被更正为CWG缺陷1244的一部分--它正确地指示了[temp.alias]中没有实际指定别名模板等同于它们所别名的模板的措辞。 其中唯一的措辞是指别名模板专门化的等价性:
当template-id引用别名模板的专门化时,它等效于通过将其template-参数替换为别名模板type-id中的template-parameters而获得的关联类型。
其意图显然是y
和z
在本例中具有相同的类型,这意味着z
和y
实际上是等价的。 但是,除非和直到决议中的措辞获得通过,否则它们不是。 今天,别名
和测试
并不等价,但别名
和test
是等价的。 这意味着is_specialization_of
是is_specialization_of
,其中alias
与test
是唯一的,这将不匹配您的部分专门化,因此是false_type
。
此外,即使采用#1286中的措辞,test
和alias
仍然不等价,原因很明显,test
采用两个模板参数,alias采用一个模板参数。 决议措辞中的示例模仿了您的示例,并阐明了此处的意图:
template<typename T, U = T> struct A;
// ...
template<typename V>
using D = A<V>; // not equivalent to A:
// different number of parameters
我认为没有模板参数列表的别名模板的名称不等同于关联类型的名称。 因为standard只指定了一种情况:
14.5.7别名模板[temp.Alias]
这很好用:
static_assert(is_specialization_of<test, alias<int>>::value, "2");