别名模板的包扩展

时间:2015-06-08 10:40:57

标签: c++ c++11 language-lawyer variadic-templates template-aliases

似乎可以在别名模板的pack参数的位置扩展 包参数。对于类或函数模板,情况并非如此:

template <class T, class... Args> struct x { using type = T; };

template <class T, class... Args> using x_t     = typename x<T, Args...>::type;
template <class... Args>          using x_fix_t = typename x<Args...>::type;

template <class... Args> auto f(Args...) -> void {
  typename x<Args...>::type v1; // OK
  x_t<Args...> v2; // Error
  x_fix_t<Args...> v3; // OK
}

更简单的案例:

template <class T, class U> using y_t = T;

template <class... Args> auto f(Args...) -> void {
  y_t<Args...> v4; // Error
}

以上代码在fc++11和{{1}中同时生成错误(即使c++14从未实例化)g++ 4.9g++ 5.1 }。

为什么不允许这样做,一般规则是什么?我认为没有理由限制这一点。这似乎是一个非常奇怪的禁令。

至于为什么不用第一个变体写clang 3.5,更清楚x_fix_t有一个强制性的第一个参数。 (例如,这是不允许x_t的原因)。但这并不重要,修复很容易。问题仍然存在:为什么?

gcc错误:

f()

clang错误:

error: pack expansion argument for non-pack parameter ‘T’ of
alias template ‘template<class T, class ... Args> using x_t = typename x::type’

1 个答案:

答案 0 :(得分:19)

这在GCC 4.8中编译但在GCC 4.9中失败,这证明它与DR1430和bug report #59498有关。 Roy Chrihfield提出的解决方案与你的完全相同:

Rewriting the code to use a struct succeeds:

template <typename T, typename ...>
struct alias { using type = T; };

template <typename ...T>
using variadic_alias = typename alias<T...>::type;

此外,Jason Merrill详细说明了它为什么会失败:

  

实际上,不,这是Core 1430的一个问题;没有办法   mangle variadic_alias没有提到别名的名称   在整修中的模板,它们应该是完全的   透明。这仅在4.8中偶然起作用,因为检查是   禁用此版本。

错误报告中不存在进一步的讨论,因此我们可以转向DR1430:

  

最初,包扩展无法扩展到固定长度   模板参数列表,但在N2555中已更改。这有效   适用于大多数模板,但会导致别名模板出现问题。

     

在大多数情况下,别名模板是透明的;什么时候用在   我们只能在依赖模板参数中替换模板。   但是,如果template-id使用包扩展,这不起作用   非可变参数。例如:

template<class T, class U, class V>
struct S {};

template<class T, class V>
using A = S<T, int, V>;

template<class... Ts>
void foo(A<Ts...>);
     

没有办法用S来表达A,所以我们需要坚持   在A上直到我们有Ts代替,因此它   需要在整理中处理。

     

目前,EDG和Clang拒绝这个测试用例,也抱怨   A. G ++的一些模板参数也是如此,但我认为是   一个bug。然而,在ABI名单上,John Spicer认为它应该是   拒绝。

     

(另见问题1558。)

     

2012年10月会议的说明:

     

CWG的共识是禁止使用这种用法,   当依赖参数不能使用别名模板时,禁止使用别名模板   只需直接替换为type-id。

     

附加说明,2013年4月:

     

再举一个例子,考虑一下:

  template<class... x> class list{};
  template<class a, class... b> using tail=list<b...>;
  template <class...T> void f(tail<T...>);

  int main() {
    f<int,int>({});
  }
     

此示例的处理存在实现差异。

换句话说,这是一个持续的问题,没有任何解决方案(AFAIC)。