如何使用 std::conditional 使所有选项都具有检查/无选项是默认值

Zsa*_*sar 2 c++ c++14

std::conditional_t可以永久嵌套:

#include <cstdint>
#include <cstring>
#include <type_traits>

enum class data_types { single_bytes, four_byte_integrals, four_byte_floats };
    
template<data_types expected_type>
std::conditional_t<expected_type == data_types::single_bytes,        uint8_t,
std::conditional_t<expected_type == data_types::four_byte_integrals, int32_t,
                                                                     float>>
parse(const uint8_t * rawBytes)
{
    using return_t = std::conditional_t<expected_type == data_types::single_bytes,        uint8_t,
                     std::conditional_t<expected_type == data_types::four_byte_integrals, int32_t,
                                                                                          float>>;
    constexpr auto length = sizeof(return_t);
    return_t result;
    std::memcpy(&result, rawBytes, length);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果所有条件均失败,则最后一个选项将作为默认情况。这可能是不希望的。

std::enable_if存在是为了在不满足条件时防止模板实例化:

#include <cstdint>
#include <cstring>
#include <type_traits>

enum class data_types { single_bytes, four_byte_integrals, four_byte_floats };

template<data_types expected_type>
std::enable_if_t<expected_type == data_types::four_byte_floats , float>
parse(const uint8_t * rawBytes)
{
    float result;
    constexpr auto length = sizeof(float);
    std::memcpy(&result, rawBytes, length);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

但嵌套std::enable_if总是std::conditional失败,即使较早的分支就足够了(不会短路):std::conditional

#include <cstdint>
#include <cstring>
#include <type_traits>

enum class data_types { single_bytes, four_byte_integrals, four_byte_floats };
    
template<data_types expected_type>
std::conditional_t<expected_type == data_types::single_bytes,        uint8_t,
std::conditional_t<expected_type == data_types::four_byte_integrals, int32_t,
std::enable_if_t<expected_type == data_types::four_byte_floats,      float>>>
parse(const uint8_t * rawBytes)
{
    using return_t = std::conditional_t<expected_type == data_types::single_bytes,        uint8_t,
                     std::conditional_t<expected_type == data_types::four_byte_integrals, int32_t,
                     std::enable_if_t<expected_type == data_types::four_byte_floats,      float>>>;
    constexpr auto length = sizeof(return_t);
    return_t result;
    std::memcpy(&result, rawBytes, length);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

发出“错误:‘struct std::enable_if<false, float>’中没有名为‘type’的类型”,例如此用途:

int main()
{
  uint8_t rawBytes[]{ 1u, 2u, 3u, 4u };
  auto x{ parse<data_types::single_bytes>(rawBytes) };
}
Run Code Online (Sandbox Code Playgroud)

我们如何定义一个依赖类型,如果没有选项有效,但只有在没有选项有效的情况下才会失败?

康桓瑋*_*康桓瑋 5

使用帮助器类将枚举值映射到类型,并且当枚举值无效时不提供成员类型别名

enum class data_types { single_bytes, four_byte_integrals, four_byte_floats };
template<data_types expected_type>
struct enum_to_type { };
template<>
struct enum_to_type<data_types::single_bytes>        { using type = uint8_t; };
template<>
struct enum_to_type<data_types::four_byte_integrals> { using type = int32_t; };
template<>
struct enum_to_type<data_types::four_byte_floats>    { using type = float; };
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它

template<data_types expected_type>
typename enum_to_type<expected_type>::type
parse(const uint8_t * rawBytes)
{
  using return_t = typename enum_to_type<expected_type>::type;
  // ...
}
Run Code Online (Sandbox Code Playgroud)

演示