别名模板的包扩展
Pack expansion for alias template
似乎只能在别名模板的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
}
以上代码在g++ 4.9
, g++ 5.1
和clang 3.5
中c++11
和c++14
都产生错误(即使f
从未实例化)。
为什么这是不允许的,一般规则是什么?我认为没有理由限制这一点。这似乎是一个非常奇怪的禁令。
至于为什么不将第一个变量写成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报告#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问题;没有办法损坏variadic_alias<T…比;没有提到别名的名字模板在变形,他们应该是完全透明的。这只在4.8中偶然有效,因为检查是版本禁用。>
在bug报告中没有进一步的讨论,所以我们可以求助于CWG 1430:
最初,包扩展不能扩展为固定长度模板参数列表,但在N2555中更改了。这是对于大多数模板都可以,但是会导致别名模板的问题。
在大多数情况下,别名模板是透明的;当它用在模板中,我们只需要替换相关的模板参数即可。但是,如果模板id使用包扩展,则无法工作non-variadic参数。例如: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...>);
没有办法表达A<Ts…>用S表示,所以我们需要保持到A上,直到我们有t来代入,因此需要在缠绕中处理。
目前,EDG和Clang拒绝这个测试用例,并抱怨a.g ++的一些模板参数也是如此,但我认为那是一个错误。然而,在ABI名单上,约翰·斯派塞(John Spicer)认为应该是这样拒绝。
(另见第1558期)
2012年10月会议纪要:
CWG一致认为这种用法应该被禁止,当依赖参数不能使用别名模板时,禁止使用别名模板直接替换为类型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)。
这是一个令人讨厌的不便,但有一个解决方案:
使using
模板接受单个typename T
,并使调用者将可变参数包装在types_t
容器中
template<typename... Ts>
struct types_t{};
,然后,从现在接受types_t
的using
,委托在另一个元函数
- 嵌套参数包扩展失败
- [temp.variadic]中关于包扩展实例化的措辞
- 模板参数部分中有关包扩展的一些混淆
- 可变参数函数参数包扩展
- c++非类型参数包扩展
- C++别名的模板参数包扩展
- 如何将参数包扩展为向量<any>
- 模板包扩展以将函数应用于连续的参数对
- C++参数包扩展
- 如何为原生UI工具包扩展Ranorex?
- 折叠表达式、参数包扩展、类成员函数中的递归
- "如果 constexpr",在 lambda 内部,在包扩展内部 - 编译器错误?
- 折叠表达式扩展包中的最大元素数
- GCC vs CLANG:将捕获的参数包扩展两次
- 未使用模板类型定义的同时参数包扩展错误
- 构造仪的类模板参数包扩展
- 使用参数包扩展生成constexpr
- 如何"duplicate"模板参数包扩展?
- 模板.参数包扩展 - 重映射类型
- 哪个编译器(如果有的话)在参数包扩展中存在错误