60

也许我错过了一些东西,但我找不到任何提示:C++17 中是否有一个与 constexpr-if 等效的 constexpr 三元运算符?

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;    
};
4

3 回答 3

49

不,没有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;    
};

它可能不是有史以来最性感的代码,但它可以完成工作。请注意,从N4487P0170 开始constexpr,lambdas在可能的情况下是默认的。

于 2017-02-23T23:54:41.037 回答
28

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

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

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

那是一种非常不同的东西。

于 2017-02-24T00:06:14.230 回答
1

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

#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>)>);
于 2021-03-12T22:02:03.450 回答