【问题标题】:Matching alias template as template argument匹配别名模板作为模板参数
【发布时间】:2017-09-22 23:08:10
【问题描述】:

考虑following code

#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)中的有什么不同?

【问题讨论】:

标签: c++ c++11 templates language-lawyer


【解决方案1】:

这是CWG issue 1286。问题是:aliastest 是否等效? [temp.type]中曾经有一个例子表明yz在这里具有相同的类型:

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 defect 1244 的一部分进行了更正 - 这正确表明[temp.alias] 中没有任何措辞实际上指定别名模板等同于它们别名的模板。那里唯一的措辞是指别名模板特化的等效性:

当一个template-id指代一个别名模板的特化时,它等价于通过替换它的template-arguments 用于别名模板的 type-id 中的 template-parameters

意图显然是 yz do 在此示例中具有相同的类型,这意味着 ZY 实际上是等效的。但除非并且直到决议中的措辞获得通过,否则它们不会。今天,aliastest 等效,但 alias&lt;int&gt;test&lt;int&gt; 。这意味着is_specialization_of&lt;alias, alias&lt;int&gt;&gt;is_specialization_of&lt;alias, test&lt;int&gt;&gt;,其中aliastest 不同,这与您的部分专业化不匹配,因此是false_type

此外,即使采用 #1286 中的措辞,testalias仍然不等价,原因很明显,test 采用两个模板参数,而别名采用一个模板参数。决议措辞中的示例模仿了您的示例并在此处阐明了意图:

template<typename T, U = T> struct A;

// ...

template<typename V>   
  using D = A<V>;      // not equivalent to A:
                       // different number of parameters

【讨论】:

  • 有趣的是,如果我们更改 test 以获取单个模板参数,那么 (2) 仍然无法使用任何 Clang 和 GCC = 4.9 已经实现了#1286。
  • @IgorR。好吧,没有采用1286。所以它可以说是不正确的。
【解决方案2】:

我认为没有模板参数列表的别名模板名称不等于关联类型的名称。因为标准只规定了一种这样的情况:

14.5.7 别名模板 [temp.alias]

  1. 当一个template-id指代一个别名模板的特化时,它等价于关联类型 通过将其模板参数替换为别名的类型 ID 中的模板参数而获得 模板。 [注意:永远不会推断出别名模板名称。-结束注释]

还有这个works fine

static_assert(is_specialization_of<test, alias<int>>::value, "2");

【讨论】:

  • 那么,为什么如果我们删除test的第二个模板参数U,一切都编译得很好?
  • 是不是因为“永远不会推导出别名模板名称”。通过尝试推断专业化的参数来选择部分专业化。当编译器试图在特化中推导出T 时,它不认为alias 是一种可能性?
  • 这实际上是 17.5.7,在this 之后;请使用永久名称,即在这种情况下为 [temp.alias]。 (可以链接到:http://eel.is/c++draft/temp.alias。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-18
  • 1970-01-01
  • 2017-01-20
相关资源
最近更新 更多