Эквивалентный троичный оператор для constexpr if?

Может быть, я что-то пропустил, но не могу найти подсказки: есть ли в 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;    
};

3 ответа

Нет, нет constexepr условный оператор. Но вы можете обернуть все это в лямбду и сразу же оценить ее ( 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;    
};

Возможно, это не самый сексуальный код, но он выполняет свою работу. Обратите внимание, что лямбды constexpr по умолчанию, где это возможно, начиная с N4487 и P0170.

Вы, кажется, действуете в убеждении, что if constexpr это оптимизация производительности. Это не так. Если вы поместите постоянное выражение в ?: В этом случае любой компилятор, который стоит использовать, выяснит, к чему он приводит, и удалит условие. Таким образом, код, который вы написали, почти наверняка скомпилируется в один вариант для определенного Mode,

Основная цель if constexpr это полностью исключить другую ветку. То есть компилятор даже не проверяет, является ли он синтаксически допустимым. Это было бы для чего-то, где вы if constexpr(is_default_constructible_v<T>)и если это правда, вы делаете T(), С регулярным if заявление, если T не является конструируемым по умолчанию, T() все равно должен быть синтаксически действительный код, даже если окружающий if предложение является константным выражением. if constexpr устраняет это требование; компилятор будет отбрасывать операторы, которые не находятся в другом условии.

Это становится еще сложнее для ?:, потому что тип выражения основан на типах двух значений. Таким образом, оба выражения должны быть допустимыми, даже если одно из них никогда не оценивается. constexpr форма ?: предположительно отбросил бы альтернативу, которая не берется во время компиляции. И поэтому тип выражения должен действительно основываться только на одном из них.

Это совсем другая вещь.

Принятый ответ также можно для удобства перевести в функцию шаблона:

      #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>)>);
Другие вопросы по тегам