三元运算符和if constexpr

3

我有时候会遇到这样的情况,基于一些 bool 值,我想调用两个返回不同类型的 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;
}

3
我看不到更好的选择。我会用你已经有的内容继续前进。 - bolov
标签分派在这里可能很有用:get(int_tag)get(string_tag),然后 val = get(tag{})std::false_typestd::true_type 可以用作标签。 - Evg
@bolov 我担心你是对的,但也许有人有一些聪明的东西要和我们分享 :) - NoSenseEtAl
1
std::variantstd::visitconstexpr的,但不确定是否更好... - Jarod42
4个回答

4

另一个选项是使用标签派发:

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

2

我不确定是否更好,但使用 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);
}

Demo


我试图使用std::get将其压缩成一行,但variant不支持constexpr,而且无论如何std::get<!use_str>看起来都很糟糕 :) - NoSenseEtAl

1
这应该可以工作:

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

实时示例


+1。但是您可以通过使用专门化来简化一些内容;例如 template <bool> struct value_chooser { static constexpr auto value = "47"; }; template <> struct value_chooser<false> { static constexpr auto value = 47; }; - max66
@max66 是的,我知道,但我发现这种方式更加一致和明确 - 因此更易读。 - Slava
@max66,我认为你的方法最好使用枚举,当你指定默认情况并覆盖某些情况时。 - Slava
同样对于整数值,从可读性的角度来看,当存在重要的默认行为和一些特殊情况时,最好采用(在我看来)。 - max66

1

我已经解决下面的代码问题,但是它相当冗长。是否有更好的方法?

在使用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"}; }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接