【问题标题】:c++ bool template avoiding if statementc ++ bool模板避免if语句
【发布时间】:2017-03-11 18:21:56
【问题描述】:

我正在寻找一种在处理模板布尔函数时避免使用 if 语句的方法。
下面的代码显示了我的情况的简化。

#include <iostream>
#include <string>

template<bool var>
void f(){
 std::cout << (var ? "TRUE" : "FALSE") << std::endl;
}

int main(int argc, char* argv[]){
    const bool b = (std::string(argv[1]).compare("TRUE") == 0);
    if (b) f<true>();
    else f<false>();
    return 0;   
}

我不想将b 作为函数f() 的参数传递,因为在实际应用中,我对性能感兴趣,我需要在关键代码中检查b 的值部分
我想要一种写法:f&lt;b&gt;();
但是这样做,我得到以下错误:
error: the value of ‘b’ is not usable in a constant expression

由于在我的应用程序中我有 4 个 bool 模板,我想避免列出这四个模板的所有组合,例如:

if(b1 && b2 && b3 && b4) f<true,true,true,true>();
else if (b1 && b2 && b3 && !b4) f<true,true,true,false>();
...

有办法解决吗?是否存在我可以以某种方式使用的快捷方式?
我也尝试使用 if 语句快捷方式 f&lt;(b?true:false)&gt;();
但我收到了与上面相同的错误。

【问题讨论】:

  • 如果它们真的是可变参数,请使用正确的工具而不是模板参数。
  • argv 在运行时已知, b 必须在编译时已知,所以你被卡住了。使 b const 不会有任何好处。
  • 是的,但不存在一种优雅的方式来写下来?
  • f(b) 有什么问题?
  • 这是在优化错误。首先,您尝试使用编译时计算来优化测试运行时值。那是行不通的。您需要在此代码中测试该变量 somewhere。其次,避免这种假设的性能损失不值得使您的代码不可读。第三,别再担心了!优化器和分支预测器将一起完成一项出色的工作,以确保运行时初始化的常量不会在每次测试时都受到惩罚。不信,自己编译一些测试用例,自己看看吧!

标签: c++ templates if-statement boolean


【解决方案1】:

我想我明白你想做什么。您需要一个查找表,它包含一堆开/关标志并运行模板的特定实例化......

这是可能的,但有点超出了快速回答所能做的范围。你需要一些适度的元编程。我要开始的地方是:

  1. 实现一个创建一组 n 标志排列的元程序。
  2. 实现将一系列标志转换为位掩码的 constexpr 函数。您将在运行时和编译时使用它。
  3. 实现一个元程序,它会根据布尔标志为您提供指向实例化的函数指针。
  4. 实现一个元程序/constexpr 函数,该函数生成由位掩码索引的此类指针数组。
  5. 在运行时使用您的布尔值调用。

实施可能需要几个小时,但应该不会那么难。

您最初的问题似乎期望将运行时值转换为编译时值,而这根本不可能。但是您可以实现一个跳转表,这样您就不必自己手写每个排列。你应该问问自己这是否真的值得,因为最终结果将更难维护,特别是如果你的团队充满了初级开发人员——我现在假设你是。很多资深开发者也看到这种东西跑到山上去。

哦,您不一定会看到任何性能改进。个人资料,不要假设。

【讨论】:

  • “这是可能的,但有点超出了快速回答的范围。” - 哇。是谁提出了这样一个想法,即 Stack Overflow 是写一些快速、手把手-已经回答的地方的地方?
【解决方案2】:

你可能想要这样的东西:

template <bool b1, bool b2, bool b3, bool b4>
void f()
{
    // Your method.
    std::cout << b1 << b2 << b3 << b4 << std::endl;   
}

template <std::size_t...Is>
void call_f_helper(int i, std::index_sequence<Is...>)
{
    using f_t = void();
    f_t* fs[] = {&f<(Is >> 0) & 1, (Is >> 1) & 1, (Is >> 2) & 1, (Is >> 3) & 1>...};

    fs[i]();
}

// The runtime dispather
void call_f(bool b1, bool b2, bool b3, bool b4)
{
    call_f_helper(b1 << 0 | b2 << 1 | b3 << 2 | b4 << 3, std::make_index_sequence<16>());  
}

Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-29
    • 2020-10-21
    相关资源
    最近更新 更多