constexpr的等效三元运算符if?

wim*_*aan 27 c++ constexpr c++17 if-constexpr

也许我错过了一些东西,但我找不到任何提示:C++ 17中有一个constexpr三元运算符,相当于constexpr-if?

template<typename Mode>
class BusAddress {
public:
    explicit constexpr BusAddress(Address device) : 
        mAddress(Mode::write ? (device.mDevice << 1) : (device.mDevice << 1) | 0x01) {}
private:
    uint8_t mAddress = 0;    
};
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 17

不,没有constexepr条件运算符.但你可以将整个东西包裹在lambda中并立即评估它(IIFE):

template<typename Mode>
class BusAddress {
public:
    explicit constexpr BusAddress(Address device)
     : mAddress([&]{
          if constexpr (Mode::write) {
            return device.mDevice << 1;
          }
          else {
            return (device.mDevice << 1) | 0x01;
          }         
        }())
     { }
private:
    uint8_t mAddress = 0;    
};
Run Code Online (Sandbox Code Playgroud)

它可能不是有史以来最性感的代码,但它完成了工作.请注意,constexprN4487P0170开始,默认情况下默认使用lambdas .

  • 当他们说 constexprambas 很强大时,他们并不是在开玩笑。今天我使用递归模板在编译时计算二项式系数。当优化 K &gt; N/2 时,这会派上用场。 (2认同)

Nic*_*las 14

你似乎是在if constexpr一种性能优化的信念下行事.事实并非如此.如果在?:子句中放置一个常量表达式,任何值得使用的编译器都将确定它解析的内容并删除条件.所以你编写的代码几乎肯定会编译成一个特定的选项Mode.

其主要目的if constexpr是完全消除其他分支.也就是说,编译器甚至不检查它是否在语法上有效.这适用于if constexpr(is_default_constructible_v<T>)你所做的事情,如果是真的,那就是你做的事情T().使用常规if语句,如果T不是默认构造,T()即使around if子句是常量表达式,仍然必须是语法上有效的代码.if constexpr删除该要求; 编译器将丢弃不在其他条件下的语句.

这变得更加复杂?:,因为表达式的类型基于两个值的类型.因此,两个表达式都需要是合法的表达式,即使其中一个表达式从未被评估过.一种constexpr形式?:可能会丢弃在编译时未采用的替代方案.因此表达式的类型应该只基于其中一个.

那是一种非常不同的事情.

  • 正是由于类型差异,我一直在寻找这样的constexpr`?:`:我想用表达式的结果移动构造一个声明为`auto`的局部变量,而常规if if constexpr则不能而不将其包装在函数中(或IIFE,请参见@Barry的答案)。我本来希望避免这种语法噪音。 (4认同)
  • 即使被丢弃的语句也必须是“语法上”有效的,但它们不需要在语义上有效(并且它们可以执行准语法操作,例如声明不存在的嵌套类型的变量)。 (3认同)
  • 编译器确实会根据 constexpr 更改调试(非优化)构建中的代码生成。因此,虽然它不是针对发布版本的优化,但它在很大程度上可以是针对在条件语句中使用 constexpr 的调试版本的优化。这在复杂模板中特别有用,其中存在许多代码路径,但根据模板参数只能有一个。过去,在尝试调试问题时,此类函数非常繁重,但使用 constexpr 可以大大减轻负担,而无需依赖编译器和调试符号信息的巧妙优化功能。 (3认同)