c++ - 别名模板的包扩展

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

似乎可以扩展包参数只有代替别名模板的包参数。对于类或函数模板,情况并非如此:

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
}

上面的代码会产生错误(即使 f 从未被实例化)同时使用 c++11c++14g++ 4.9 , g++ 5.1clang 3.5 .

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

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

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

叮当错误:
error: pack expansion used as argument for non-pack parameter of
alias template   x_t<Args...> v2;

最佳答案

这在 GCC 4.8 中编译但在 GCC 4.9 中失败,这证明它与 CWG 1430 和 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 详细说明了为什么它会失败:

Actually, no, this is very much a Core 1430 issue; there's no way to mangle variadic_alias<T...> without mentioning the name of an alias template in the mangling, and they're supposed to be entirely transparent. This only works in 4.8 by accident because checking is disabled for the release.


错误报告中没有进一步的讨论,所以我们可以转向 CWG 1430:

Originally, a pack expansion could not expand into a fixed-length template parameter list, but this was changed in N2555. This works fine for most templates, but causes issues with alias templates.

In most cases, an alias template is transparent; when it's used in a template we can just substitute in the dependent template arguments. But this doesn't work if the template-id uses a pack expansion for non-variadic parameters. For example:

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...>);

There is no way to express A<Ts...> in terms of S, so we need to hold onto the A until we have the Ts to substitute in, and therefore it needs to be handled in mangling.

Currently, EDG and Clang reject this testcase, complaining about too few template arguments for A. G++ did as well, but I thought that was a bug. However, on the ABI list John Spicer argued that it should be rejected.

(See also issue 1558.)

Notes from the October, 2012 meeting:

The consensus of CWG was that this usage should be prohibited, disallowing use of an alias template when a dependent argument can't simply be substituted directly into the type-id.

Additional note, April, 2013:

For another example, consider:

  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>({});
  }

There is implementation variance in the handling of this example.


换句话说,这是一个持续存在的问题,看不到任何解决方案 (AFAIC)。

关于c++ - 别名模板的包扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60131687/

相关文章:

C++ 解引用数组

C++11 就地构造混淆

c++ - TR2 W.R.T. 的状态和内容C++ 规范

c++ - 使用 {} 的函数重载解析

c++ - 具有空 mem-initializer-list 和空主体的构造函数

c++ - 在一个线程上用 ppoll 阻塞,在另一个线程上读/写同一个 fds 是否安全?

c++ - Boost tribool 在 C++ 中导致从右到左的条件评估

c++ - 如何显式调用其转换类型 ID 包含占位符说明符的转换函数

c++ - 如何像标准输入一样在Windows中的gcc中逐行读取命令输出?

c++ - 获取重载函数模板的地址是可能的,有时