constexpr的等效三元运算符if?

时间:2016-12-07 07:44:45

标签: 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;    
};

2 个答案:

答案 0 :(得分:12)

您似乎认为if constexpr是性能优化。它不是。如果在?:子句中放置一个常量表达式,任何值得使用的编译器都会找出它解析的内容并删除条件。因此,您编写的代码几乎肯定会编译为单个选项,对于特定的Mode

if constexpr的主要目的是完全消除另一个分支。也就是说,编译器甚至不检查它是否在语法上有效。这适用于您if constexpr(is_default_constructible_v<T>)的内容,如果属实,则执行T()。使用常规if语句,如果T不是默认可构造的,则T()仍然必须是语法上有效的代码,即使周围的if子句是常量表达式。 if constexpr删除了该要求;编译器将丢弃不属于其他条件的语句。

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

这是一种非常不同的事情。

答案 1 :(得分:0)

为方便起见,也可以将接受的答案翻译成模板函数:

#include <type_traits>
#include <utility>

template <bool cond_v, typename Then, typename OrElse>
decltype(auto) constexpr_if(Then&& then, OrElse&& or_else) {
    if constexpr (cond_v) {
        return std::forward<Then>(then);
    } else {
        return std::forward<OrElse>(or_else);
    }
}

// examples

struct ModeFalse { static constexpr bool write = false; };
struct ModeTrue { static constexpr bool write = true; };

struct A {};
struct B {};

template <typename Mode>
auto&& test = constexpr_if<Mode::write>(A{}, B{});

static_assert(std::is_same_v<A&&, decltype(test<ModeTrue>)>);
static_assert(std::is_same_v<B&&, decltype(test<ModeFalse>)>);

const A a;
B b;

template <typename Mode>
auto&& test2 = constexpr_if<Mode::write>(a, b);

static_assert(std::is_same_v<const A&, decltype(test2<ModeTrue>)>);
static_assert(std::is_same_v<B&, decltype(test2<ModeFalse>)>);