我的编译器不支持if constexpr
,但我被它的好处所吸引。
我必须拥有它 - 即使它可能是假的。
此代码是我模仿if constexpr
行为的尝试
目标是使行(###)只出现在1个函数中: -
#include <iostream>
using namespace std;
template<bool Flag,typename F> constexpr typename std::enable_if<!Flag, void>::type iter_(F f,int i1){
f(i1); //No! The compiler still tried to compile even Flag=true
}
template<bool Flag,typename F> constexpr typename std::enable_if<Flag, void>::type iter_(F f,int i1){ }
template<bool Flag,typename F> constexpr typename std::enable_if<Flag, void>::type iter_(F f,int i1,int i2){
f(i1,i2); //No! The compiler still tried to compile even Flag=false
}
template<bool Flag,typename F> constexpr typename std::enable_if<!Flag, void>::type iter_(F f,int i1,int i2){}
template<bool Flag,typename F> constexpr void fff( F f ){
for(int n=0;n<5;n++){//fake loop, the real situation is very complex
//### some horror code appeared here, but omitted
if(Flag){//attempt to mimic "if constexpr"
iter_<true>(f,1,2);
}else{
iter_<false>(f,3);
}
}
}
这是它的用法: -
template<typename F> constexpr void fff1( F f ){fff<false>(f);} //usage
template<typename F> constexpr void fff2( F f ){fff<true>(f);} //usage
int main() {
// your code goes here
auto f1=[&](int a){
cout<<a<<" ";
};
auto f2=[&](int a,int b){
cout<<a<<" "<<b<<endl;
};
fff1(f1);
fff2(f2);
return 0;
}
我收到了编译错误:
prog.cpp: In instantiation of 'constexpr typename std::enable_if<Flag, void>::type iter_(F, int, int) [with bool Flag = true; F = main()::<lambda(int)>; typename std::enable_if<Flag, void>::type = void]':
prog.cpp:16:18: required from 'constexpr void fff(F) [with bool Flag = false; F = main()::<lambda(int)>]'
prog.cpp:22:61: required from 'constexpr void fff1(F) [with F = main()::<lambda(int)>]'
prog.cpp:33:9: required from here
prog.cpp:9:3: error: no match for call to '(main()::<lambda(int)>) (int&, int&)'
f(i1,i2);
^
prog.cpp:9:3: note: candidate: void (*)(int) <conversion>
prog.cpp:9:3: note: candidate expects 2 arguments, 3 provided
从错误中可以清楚地看到,即使函数有 std :: enable_if [有效 FALSE] , 编译器仍然编译函数内部的代码。 - 那很不好。
我需要编辑哪些部分?
......还是有其他选择吗?
......或者根本不可能模仿if constexpr
(这就是它最终被引入的原因)?
答案 0 :(得分:3)
阅读本文:http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0128r1.html
我们不能用现有的语言功能吗?
John Spicer在c ++ std-ext-17099中建议使用多态lambda 结合决策模板将提供足够的 设施无需添加新的语言功能。调用 该决策模板看起来大致如下:
template <int arg, typename ... Args> int do_something(Args... args) { return static_if<sizeof...(args)>::get( [](auto x, auto y) { return x+y; }, [](auto x) { return *x; })(args...); }
现在,与提议的语言工具相比,我们做了
template <int arg, typename ... Args> int do_something(Args... args) { constexpr if (sizeof...(args)) { return (args + ...); } constexpr_else { return *args...; } }
现在这是另一种选择。如果不同的分支返回不同的类型,它会变得更复杂。
此外,
我必须在这里指出一些事情:
我可以在constexpr中返回,中断,继续并转到if 块。我不能在lambda中做到这一点。
虽然我很聪明 我发现,使用lambdas建立新的控制设施的支持者 constexpr如果解决方案无限可读。
此外,
理查德史密斯解释说:是的,当实例化一个函数模板时,所有的 其中的声明/语句/表达式被实例化,并且 其中包括本地类,通用lambdas等中的部分。
这种通用lambda体的实例化实际上是必要的 我们的语言语义 - 计算通用lambda的捕获 在功能模板中,专业化依赖于我们已经 实例化完整闭包类型及其调用操作符模板 到了我们知道odr-uses在哪里的地步 身体内的非依赖性完整表达。
相比之下,constexpr的意图是没有采取分支 没有实例化。