【问题标题】:Alternatives to many nested std::conditional_t?许多嵌套 std::conditional_t 的替代品?
【发布时间】:2018-08-30 07:42:49
【问题描述】:

我发现许多嵌套的 std::conditional_t 难以阅读,因此我选择了不同的模式(在具有自动返回类型的函数上调用 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 慢(假设我需要实例化的类型比我只使用内置类型的示例中的要广泛得多)。

附:这是一个玩具示例,IRCode 我将处理一些更复杂的类型。

【问题讨论】:

  • 不是您的 Q 的答案,但您可以将 return return_void(); 替换为 return void(); - 如果没有别的实现细节,请少做一个
  • return; 也可以。
  • if constexpr,如果有的话,应该比任何基于专业化或基于 SFINAE 的编译速度

标签: c++ templates typetraits if-constexpr


【解决方案1】:

就个人而言,我觉得这里最清晰的方法是“数据驱动”。将条件放在表中(编写为类模板的特化)并让编译器进行模式匹配以确定类型更短、更不容易出错并且更易于阅读或扩展。

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 - 显然没有一种适合所有方法的方法。我真的不能评论这样一个模糊的标准。这只是你没有提到的一个替代方案,所以我觉得它值得作为一个选项添加。
【解决方案2】:

由于std::disjunction&lt;Args...&gt; 继承自Args... 中的第一个类型,其valuetrue,或者如果不存在这种类型,则Args... 中的最后一个类型,我们可以(ab)使用它来生成多路分支:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 1970-01-01
    • 2015-11-24
    相关资源
    最近更新 更多