模仿 "if constexpr" 行为,不可能?
mimic "if constexpr" behavior, impossible?
我的编译器不支持 if constexpr
,但我被它的好处所吸引。
我必须拥有它 - 即使它可能是假的。
此代码是我模仿 if constexpr
行为的尝试。
objective 是使行 (###) 仅出现在 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[ effective FALSE],
编译器仍然编译函数内部的代码。
- 那很不好。
我必须编辑哪些部分?
...或者有其他选择吗?
...或者根本不可能模仿 if constexpr
(这就是它最终被引入的原因)?
读这个:http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0128r1.html
Can't we do this with existing language features?
John Spicer suggested in c++std-ext-17099 that polymorphic lambdas
combined with a decision-making template would provide an adequate
facility without a need to add new language features. The invocation
of that decision-making template looks roughly like this:
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...);
}
Now, in comparison, with the proposed language facility, we do
template <int arg, typename ... Args> int do_something(Args... args) {
constexpr if (sizeof...(args)) {
return (args + ...);
} constexpr_else {
return *args...;
}
}
现在这是一种替代方法。如果不同的分支 return 不同类型,它会变得更复杂。
此外,
I must point out some things here:
I can return, break, continue and goto from within a constexpr if
block. I can not do that from within the lambda.
While I am a big
proponent of using lambdas to create new control facilities, I find
the constexpr if solution infinitely more readable.
此外,
Richard Smith explained the following:
Right, when a function template is instantiated, all of the
declarations/statements/expressions within it are instantiated, and
that includes pieces inside local classes, generic lambdas, and so on.
This instantiation of generic lambda bodies is in fact necessary for
our language semantics -- computing the captures of a generic lambda
within a function template specialization relies on us having already
instantiated the complete closure type and its call operator template
to the point that we know where the odr-uses are within the
non-dependent full-expressions within the body.
相比之下,constexpr if 的意图是不采取分支
未实例化。
我的编译器不支持 if constexpr
,但我被它的好处所吸引。
我必须拥有它 - 即使它可能是假的。
此代码是我模仿 if constexpr
行为的尝试。
objective 是使行 (###) 仅出现在 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[ effective FALSE],
编译器仍然编译函数内部的代码。
- 那很不好。
我必须编辑哪些部分?
...或者有其他选择吗?
...或者根本不可能模仿 if constexpr
(这就是它最终被引入的原因)?
读这个:http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0128r1.html
Can't we do this with existing language features?
John Spicer suggested in c++std-ext-17099 that polymorphic lambdas combined with a decision-making template would provide an adequate facility without a need to add new language features. The invocation of that decision-making template looks roughly like this:
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...); }
Now, in comparison, with the proposed language facility, we do
template <int arg, typename ... Args> int do_something(Args... args) { constexpr if (sizeof...(args)) { return (args + ...); } constexpr_else { return *args...; } }
现在这是一种替代方法。如果不同的分支 return 不同类型,它会变得更复杂。
此外,
I must point out some things here:
I can return, break, continue and goto from within a constexpr if block. I can not do that from within the lambda.
While I am a big proponent of using lambdas to create new control facilities, I find the constexpr if solution infinitely more readable.
此外,
Richard Smith explained the following:
Right, when a function template is instantiated, all of the declarations/statements/expressions within it are instantiated, and that includes pieces inside local classes, generic lambdas, and so on.
This instantiation of generic lambda bodies is in fact necessary for our language semantics -- computing the captures of a generic lambda within a function template specialization relies on us having already instantiated the complete closure type and its call operator template to the point that we know where the odr-uses are within the non-dependent full-expressions within the body.
相比之下,constexpr if 的意图是不采取分支 未实例化。