【发布时间】:2020-03-12 10:46:06
【问题描述】:
我偶然发现了typedef 和我想了解的可变参数模板参数之间的奇怪交互。以下代码使用 clang 编译,但使用 GCC 时出错:
template<typename T> // no error if this is not a template
struct Traits;
#pragma GCC diagnostic ignored "-Wunused-parameter"
template<typename ...args>
void function(args... e) {}
template<typename T>
struct Caller {
typedef typename Traits<T>::types traits_types; // no error if this is changed to a 'using' directive
template<typename ...types> // no error if the pack is converted to a single parameter
static void method(types... e) {
function<traits_types>(e...);
}
};
GCC 行为
当我用 GCC 编译(而不是链接)这个时,我在第 14 行得到一个错误:
$ g++-9.2.0 -Wall -Wpedantic -Wextra -std=c++11 -c test.cpp
test.cpp: In static member function ‘static void Caller<T>::method(types ...)’:
test.cpp:14:31: error: parameter packs not expanded with ‘...’:
14 | function<traits_types>(e...);
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~
test.cpp:14:31: note: ‘types’
$
它的作用就像 GCC 首先替换 traits_types 的定义,这将产生
template<typename ...types>
static void method(types... e) {
function<typename Traits<T>::types>(e...);
}
然后评估模板参数替换,此时它将标记types 的最后一次出现视为未扩展的参数包并相应地产生错误。
我已经使用 GCC 6.4.0、7.3.0、8.2.0、8.3.0、9.1.0 和 9.2.0 以及几个旧版本对此进行了测试,并且所有版本的行为都是一致的其中。
clang 行为
但是,当我用 clang 编译它时,它工作正常。
$ clang++-8 -Wall -Wpedantic -Wextra -std=c++11 -c test.cpp
$
这似乎首先替换参数包types,然后然后处理名称traits_types。
我在 clang 6.0.0、7.0.1 和 8.0.1 以及几个旧版本中始终看到这种行为。
问题
在标准 C++11 中,GCC 给出的错误是正确的,还是代码有效?还是未定义/实现定义/否则未指定?
我浏览了cppreference.com's content on templates and typedefs 的大部分内容,但没有找到任何明确解决此案例的内容。我还检查了其他几个问题(1、2、3、4、5 等),就我而言,所有这些问题看起来都相似但并不完全适用于这种情况可以说。
如果这实际上是一个编译器错误,那么在错误跟踪器中提供一个指向相关问题的链接,确认 GCC(或 clang,如果适用)没有正确处理这个问题,就可以很好地解决这个问题。
【问题讨论】:
标签: c++ c++11 gcc compiler-errors variadic-templates