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)
我们如何定义一个依赖类型,如果没有选项有效,但只有在没有选项有效的情况下才会失败?
使用帮助器类将枚举值映射到类型,并且当枚举值无效时不提供成员类型别名
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)