许多嵌套的std :: conditional_t的替代方案是什么?

5

我发现许多嵌套的std::conditional_t很难阅读,因此我选择了一种不同的模式(在具有auto返回类型的函数上调用decltype):

template<bool is_signed, std::size_t has_sizeof>
auto find_int_type(){
    static_assert(sizeof(int)==4);
    if constexpr(is_signed){
        if constexpr(has_sizeof==4){
            return int{};
        } else if constexpr (has_sizeof==8){
            return std::int64_t{};
        } else {
            return;
        }
    } else {
        if constexpr(has_sizeof==4){
            return (unsigned int){};
        }
        else if constexpr (has_sizeof==8){
            return std::uint64_t{};
        } else {
            return;
        }
    } 
}

static_assert(std::is_same_v<int, decltype(find_int_type<true, 4>())>);
static_assert(std::is_same_v<unsigned int, decltype(find_int_type<false, 4>())>);
static_assert(std::is_same_v<void, decltype(find_int_type<false, 3>())>);
static_assert(std::is_same_v<void, decltype(find_int_type<false, 5>())>);
static_assert(std::is_same_v<std::int64_t, decltype(find_int_type<true, 8>())>);
static_assert(std::is_same_v<std::uint64_t, decltype(find_int_type<false, 8>())>);
static_assert(std::is_same_v<void, decltype(find_int_type<false, 9>())>);

我的问题是:

有更好的方法吗?

相比于std::conditional_t,这种方式编译速度更慢吗?(假设我需要实例化的类型比此示例中使用的内置类型更加昂贵)。

P.S. 这只是一个玩具示例,我将处理一些更复杂的类型的IRCode。


2
不是针对你的问题的答案,但你可以将 return return_void(); 替换为 return void(); - 如果没有其他实现细节,那就少了一个。 - StoryTeller - Unslander Monica
只需 return; 即可。 - Evg
如果有的话,if constexpr 应该比任何基于特化或 SFINAE 的东西编译速度要快得多。 - n. m.
2个回答

6

个人而言,我认为这里最清晰的方法是“数据驱动”。将标准放在一个表格中(作为类模板的特殊化写入),让编译器进行模式匹配以确定类型,这样更短、更少出错,并且更易于阅读或扩展。

template<bool is_signed, std::size_t has_sizeof>
struct find_int_type_impl { using type = void; }; // Default case

template<> struct find_int_type_impl<true,  4> { using type = std::int32_t;  };
template<> struct find_int_type_impl<true,  8> { using type = std::int64_t;  };
template<> struct find_int_type_impl<false, 4> { using type = std::uint32_t; };
template<> struct find_int_type_impl<false, 8> { using type = std::uint64_t; };

template<bool is_signed, std::size_t has_sizeof>
using find_int_type = typename find_int_type_impl<is_signed, has_sizeof>::type;

这在这种情况下非常好,但是当条件是一些复杂的constexpr bool返回函数时怎么办? - NoSenseEtAl
1
@NoSenseEtAl - 显然,没有一种适合所有情况的方法。我无法对这样模糊的标准发表评论。这只是你没有提到的另一种选择,所以我觉得值得添加作为一个选项。 - StoryTeller - Unslander Monica

1

由于 std::disjunction<Args...> 继承自 Args... 中第一个 valuetrue 的类型,或者如果不存在这样的类型,则继承自 Args... 中的最后一个类型,因此我们可以(滥用)它来产生多路分支:

template<class... Args>
using select = typename std::disjunction<Args...>::type;

template<bool V, class T>
struct when {
    static constexpr bool value = V;
    using type = T;
};

template<bool is_signed, std::size_t has_sizeof>
using find_int_type = select<
    when<is_signed, select<
        when<has_sizeof==4, int>,
        when<has_sizeof==8, std::int64_t>,
        when<false, void>
    >>,
    when<!is_signed, select<
        when<has_sizeof==4, unsigned int>,
        when<has_sizeof==8, std::uint64_t>,
        when<false, void>
    >>
>;

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