Тернарный оператор и если constexpr - PullRequest
0 голосов
/ 11 октября 2018

У меня есть ситуации, когда иногда, основываясь на некоторых bool, я хочу вызвать 2 constexpr функции, которые возвращают разные типы и присваивают ей auto константу.

К сожалению, троичному оператору нужны типы, чтобы быть «похожими».

У меня есть обходной путь в коде ниже, но это довольно многословно.Есть ли лучший способ?

#include <iostream>
#include <string>

constexpr int get_int(){
    return 47;
}

constexpr std::string_view get_string(){
    return "47";
}

constexpr bool use_str = false;

constexpr auto get_dispatch(){
    if constexpr(use_str){
        return get_string();
    } else{
        return get_int();
    }

}
int main()
{
    // what I want : constexpr auto val =  use_str ? get_string():get_int();
    // what works:
    constexpr auto val = get_dispatch();
    std::cout << val << std::endl;
}

Ответы [ 4 ]

0 голосов
/ 11 октября 2018

У меня есть обходной путь в коде ниже, но это довольно многословно.Есть ли лучший способ?

Работая с C ++ 17, вы можете использовать if constexpr, и мне кажется, это хорошее решение.

Если вы действительно хотите что-то другое,Я предлагаю способ, основанный на полной специализации шаблонной функции (смесь решений Evg и Slava)

Я имею в виду что-то как

#include <iostream>
#include <string>

template <bool>
constexpr auto get_value ()
 { return 47; }

template <>
constexpr auto get_value<true> ()
 { return std::string_view{"47"}; }

int main()
 {
    constexpr auto use_str = false;
    constexpr auto val     = get_value<use_str>();

    std::cout << val << std::endl;
}

Как указывал Slava, шаблонная функция со значением по умолчаниюверсия и явная специализация для одного случая могут быть менее читабельными.

Таким образом, если вы предпочитаете вариант, более подробный, но более читабельный, вы можете написать две явные специализации для get_value() следующим образом

template <bool>
constexpr auto get_value ();

template <>
constexpr auto get_value<false> ()
 { return 47; }

template <>
constexpr auto get_value<true> ()
 { return std::string_view{"47"}; }
0 голосов
/ 11 октября 2018

Другой вариант - использовать диспетчеризацию тегов:

constexpr int get(std::false_type) {
    return 47;
}

constexpr std::string_view get(std::true_type) {
    return "47";
}

int main() {
    constexpr auto val = get(std::bool_constant<use_str>{});
    std::cout << val << std::endl;
}
0 голосов
/ 11 октября 2018

Не уверен, что лучше, но с std::variant:

int main()
{
    using my_variant = std::variant<int, std::string_view>;
    constexpr auto val =  use_str ? my_variant{get_string()} : my_variant{get_int()};
    std::visit([](const auto& v) {std::cout << v << std::endl;}, val);
}

Демо

0 голосов
/ 11 октября 2018

это должно работать:

template <bool>
struct value_chooser;

template<>
struct value_chooser<true>
{
    static constexpr auto value = "47";
};

template<>
struct value_chooser<false>
{
    static constexpr auto value = 47;
};

int main()
{
    auto value1 = value_chooser<true>::value;
    auto value2 = value_chooser<false>::value;
}

живой пример

...