[英]Pack expansion for alias template
似乎包参数只能在别名模板的包参数的位置进行扩展。 对于类或函数模板,情况并非如此:
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 和错误报告 #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 中偶然有效,因为该版本禁用了检查。
错误报告中没有进一步的讨论,所以我们可以转向 CWG 1430:
最初,包扩展不能扩展为固定长度的模板参数列表,但在 N2555 中更改了这一点。 这适用于大多数模板,但会导致别名模板出现问题。
在大多数情况下,别名模板是透明的; 当它在模板中使用时,我们可以只替换依赖模板参数。 但是,如果模板 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<Ts...>,所以我们需要保持 A,直到我们有 Ts 来替代,因此它需要在 mangling 中处理。
目前,EDG 和 Clang 拒绝了这个测试用例,抱怨 A.G++ 的模板参数太少,但我认为这是一个错误。 但是,在 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)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.