【问题标题】:mimic "if constexpr" behavior, impossible?模仿“if constexpr”行为,不可能吗?
【发布时间】:2016-08-24 14:11:04
【问题描述】:

我的编译器不支持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(这就是它最终引入的原因)?

【问题讨论】:

  • 是的,模板内的所有代码都必须有效。所以没有办法让if 有一个对模板无效的分支,并且仍然能够为该模板实例化。
  • 你在说什么if constexpr? C++11 中没有这样的东西...
  • @rubenvb 如果 constexpr 将在 C++17 中使用
  • @Eugene 问题是在发表评论时仍标记为 c++11。
  • 专业化,不要使用if

标签: c++ templates if-statement constexpr c++17


【解决方案1】:

阅读: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 中返回、中断、继续和转到,如果 堵塞。我不能在 lambda 中做到这一点。

  • 虽然我是个大人物 我发现使用 lambdas 来创建新的控制设施的支持者 constexpr if 解决方案的可读性无限。

进一步,

理查德·史密斯解释如下:

没错,当一个函数模板被实例化时,所有的 其中的声明/语句/表达式被实例化,并且 这包括本地类中的片段、通用 lambda 等等。

这种泛型 lambda 体的实例化实际上对于 我们的语言语义——计算通用 lambda 的捕获 在函数模板特化中依赖于我们已经 实例化完整的闭包类型及其调用运算符模板 以至于我们知道 odr-uses 在 体内的非依赖全表达式。

相比之下,constexpr if 的意图是分支没有被采用 没有实例化。

【讨论】:

  • 请注意,Boost.Hana 有这样一个功能:hana::if_。就实例化而言,如果它们是通用 lambda,它不会实例化未采用的分支。根据 Richard 的评论,这背后可能还有更多代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-30
  • 1970-01-01
  • 2019-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多