编辑-在下面的原始帖子中测试此的确切最小代码是,但这是两个大块。抱歉,这里是一件。注释掉main
中的实例化,然后一次将它们取消注释就可以看出我在这篇文章中描述的行为。
template <typename... TsOuter>
struct Outer
{
template <TsOuter...>
static void InnerFunc() {};
};
int main(int argc, char** argv)
{
Outer<int, int>::InnerFunc<1, 1>(); // Should work. Works on MSVC, fails on g++
Outer<int, int>::InnerFunc(); // Should fail. Works on both compilers
Outer<int, int>::InnerFunc<>(); // Should fail. Works on both compilers
Outer<int, int>::InnerFunc<1>(); // Should fail. Works on MSVC, fails on g++
Outer<int, int>::InnerFunc<1, 1, 1>(); // Should fail. Fails on both compilers
Outer<int, int>::InnerFunc<nullptr, nullptr>(); // Should fail. Fails on both compilers.
}
编辑-我无法包含我正在使用的编译器版本,由此可以看到我描述的行为:
我看到了我认为错误的编译器行为-在Microsoft C ++和g ++中。我认为编译器应该成功编译时会给出错误,而当我认为应该给出错误时它们就会成功编译。越野车(?)编译器的行为在两个编译器之间并不完全相同。
我的问题是:编译器确实有错误,还是我所理解的某个地方有错误?规范是否表示未定义以下代码的编译器行为?
当带有作为参数包的模板参数的模板类定义成员函数模板,该成员函数模板使用该类的参数包作为其模板参数时,就会发生此问题。当我实例化该成员函数模板时
奇怪的是,如果成员模板是成员模板 class 而不是成员模板函数,那么一切都将按照我的预期工作。
这是模板类定义:
template <typename... TsOuter>
struct Outer
{
template <TsOuter...>
struct InnerClass {};
template <TsOuter...>
static void InnerFunc() {};
};
请注意InnerClass
和InnerFunc
的模板参数取决于Outer
的模板参数。
我将Outer
实例化为Outer<int, int>
。这样就声明了InnerClass
template <int,int>
struct InnerClass {};
和InnerFunc
template <int, int>
static void InnerFunc() {};
实例化InnerClass
时,编译器的行为(MSVC和g ++)都符合我的理解:
Outer<int, int>::InnerClass<1, 1> x2 {}; // OK
Outer<int, int>::InnerClass x2 {}; // ERROR - No template arguments provided for InnerClass
Outer<int, int>::InnerClass<> x2 {}; // ERROR - <> does not match <int, int> (to few template arguments)
Outer<int, int>::InnerClass<1> x1 {}; // ERROR - <1> does not match <int, int> (to few template arguments)
Outer<int, int>::InnerClass<1, 1, 1> x3 {}; // ERROR - <1,1,1> does not match <int, int> (to many template arguments)
Outer<int, int>::InnerClass<nullptr, nullptr> x4 {}; // ERROR - <nullptr, nullptr> does not match <int, int> (template argument types do not match template parameter types)
但是,与InnerFunction
不同。我对InnerFunction
的期望与InnerClass
相同。但是我看到的是:
Outer<int, int>::InnerFunc<1,1>(); // Should work. Works on MSVC, fails on g++
Outer<int, int>::InnerFunc(); // Should fail. Works on both compilers
Outer<int, int>::InnerFunc<>(); // Should fail. Works on both compilers
Outer<int, int>::InnerFunc<1>(); // Should fail. Works on MSVC, fails on g++
Outer<int, int>::InnerFunc<1,1,1>(); // Should fail. Fails on both compilers
Outer<int, int>::InnerFunc<nullptr, nullptr>(); // Should fail. Fails on both compilers.
如果Outer
具有非可变模板参数,那么我看不到此问题-一切对InnerClass
和InnerFunction
均正常。
鉴于我在此描述的编译器的行为,我是否纠正它们都存在错误?如果是这样,它们对我来说似乎是非常重要的错误。
谢谢!
答案 0 :(得分:4)
这确实是gcc中的编译器错误。
以下内容用于测试
template <typename... TsOuter>
struct Outer
{
template <TsOuter... n>
static void InnerFunc() {
static int i[2] = { n... };
};
};
int main() {
typedef Outer<int, int> t;
t::InnerFunc<1, 1>();
}
这在clang和msvc中可以正常编译。
但是在gcc中,错误是:
<source>:13:24: error: no matching function for call to 'Outer<int, int>::InnerFunc<1, 1>()'
13 | t::InnerFunc<1, 1>();
| ^
<source>:5:17: note: candidate: 'template<TsOuter ...n> static void Outer<TsOuter>::InnerFunc() [with TsOuter ...n = {n ...}; TsOuter = {int, int}]'
5 | static void InnerFunc() {
| ^~~~~~~~~
<source>:5:17: note: template argument deduction/substitution failed:
<source>:13:24: error: wrong number of template arguments (2, should be 1)
13 | t::InnerFunc<1, 1>();
| ^
哪个建议gcc认为应该有一个参数,而不是2,错误地没有扩展参数包。
如果您确实传递了一个参数而不是2:
t::InnerFunc<1>();
<source>:13:21: internal compiler error: tree check: accessed elt 1 of tree_vec with 0 elts in tsubst_pack_expansion, at cp/pt.c:12169
13 | t::InnerFunc<1>();
| ^
我实际上不确定参数如何作为模板参数打包,但是绝对不应该是内部编译器错误。我无法在本地g ++安装上重现此错误,但错误会被切断(打印“模板参数推导/替换失败:”,然后什么也没有)