我不明白为什么这不会被编译:
#include <iostream>
template<int I1,int ...Is>
int getProdSeq() {
if(sizeof...(Is)==0)
return I1;
else
return I1*getProdSeq<Is...>();
}
int main() {
int i = getProdSeq<9,7,8>();
std::cout<<i<<std::endl;
}
在对函数的最后一次递归调用中,...IS
应为空,因此应该采用第一个if-branch。编译器也确认了这一点(...IS
为空):
main.cpp: In instantiation of 'int getProdSeq() [with int I1 = 8; int ...Is = {}]':
但编译器也会发出以下错误:
main.cpp:5:5: note: template argument deduction/substitution failed:
main.cpp:10:36: note: couldn't deduce template parameter 'I1'
如果函数确实是使用空参数包调用的,那么这个错误是有意义的,但是这不应该是这种情况,因为我用第一个if语句规避了这个问题。为什么编译器仍在检查else分支?
答案 0 :(得分:2)
无法编译,因为:
constexpr
。if
语句未评估编译时间,因此编译器必须生成两个分支,从而导致编译器错误。这可以用C ++ 17 if contexpr
来解决。 示例(使用gcc-7 -std=gnu++1z
编译):
template<int I1, int ...Is>
constexpr int getProdSeq() {
if constexpr(sizeof...(Is)==0)
return I1;
else
return I1*getProdSeq<Is...>();
}
答案 1 :(得分:1)
如果在实例化
template<int I1,int ...Is>
int getProdSeq() {
...Is
参数包为空,然后是以下调用:
getProdSeq<Is...>();
实例化getProdSeq<>
,当然不存在。仅仅因为前面的if
语句永远不会执行它,并不意味着它仍然必须是可编译的。模板扩展的结果必须是有效的C ++代码,而事实并非如此。仅仅因为if
语句else
clasuse永远不会执行,并不会改变else
内的任何内容必须仍然是有效C ++代码的事实。
一种方法是使用两个模板:
#include <iostream>
template<int I1>
int getProdSeq() {
return I1;
}
template<int I1,int I2, int ...Is>
int getProdSeq() {
return I1*getProdSeq<I2, Is...>();
}
int main() {
int i = getProdSeq<9,7,8>();
std::cout<<i<<std::endl;
}
答案 2 :(得分:0)
如果函数确实是使用空参数包调用的,那么这个错误是有意义的,但是这不应该是这种情况,因为我用第一个if语句规避了这个问题。为什么编译器仍在检查else分支?
您的所有代码都会将编译器的所有阶段都传递到优化步骤。例如,对于clang / llvm,分支可能仅在转换为IR后才被消除。 因此,类型检查/推断/ ...在“坏代码”被丢弃之前的某处失败。
所以想象你写了
int x;
if (false) {
x = '123';
} else {
x = 0;
}
这仍然是错误的,即使if-branch永远不会执行。