2017-02-17 35 views
0

我不明白为什么这并不会编译:分公司可变参数模板

#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应该是空的,所以第一个,如果分支应采取。编译器也证实了这一点(即...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分支?

回答

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

它无法编译,因为:

  1. 功能是不是constexpr声明。
  2. 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...>(); 
} 
+0

因此,没有机会为这个代码工作(除非你彻底改变它),而第二个'C++ 17''constexpr'? – FloriHe

+0

@FloriHe Sam Varshavchik已经提供了C++ 11版本。 –

0

Well this error would make sense if the function was indeed called with an empty parameter-pack, but this shouldn't be the case as I circumvent this problem with the first if-statement. Why is the compiler still checking the else branch?

所有的代码经过编译器的各个阶段到优化步骤。例如,对于clang/llvm,这些分支可能只会在转换到IR之后才被淘汰。 因此,类型检查/减除/ ...失败前的“恶意代码”被丢弃的地方。

所以,想象一下你写

int x; 
if (false) { 
    x = '123'; 
} else { 
    x = 0; 
} 

这仍然是错误的,即使如果分支将永远不会执行。