在std :: conditional中使用sizeof不完整类型

陳 力*_*陳 力 5 c++ type-traits template-meta-programming incomplete-type c++17

这是一个最小的例子:

struct incomplete_type;

template<typename T>
struct foo
{
    using type = std::conditional_t<std::is_arithmetic_v<T>,
        std::conditional_t<sizeof(T) < sizeof(void*), int, float>,
        double>;
};
Run Code Online (Sandbox Code Playgroud)

foo<incomplete_type> f;将导致错误,因为它将使用类型执行sizeof,即使incomplete_type它不是算术类型(哇,它不会逻辑地进入sizeof分支).现场演示

所以,我想推迟 sizeof:

第一次尝试(失败)

template<typename T>
auto
foo_aux()
{
    if(sizeof(T) < sizeof(T*))
        return 0;
    else
        return 0.0f;
}
Run Code Online (Sandbox Code Playgroud)

conditional_t<std::is_arithmetic_v<T>, decltype(foo_aux<T>()), double> 仍会触发相同的错误.

第二次尝试(失败)

template<typename T, bool>
struct foo_aux_aux
{
    using type = float;
};
template<typename T>
struct foo_aux_aux<T, true>
{
    using type = int;
};

template<typename T, bool = false>
struct foo_aux : foo_aux_aux<T, sizeof(T) < sizeof(void*)>
{};
Run Code Online (Sandbox Code Playgroud)

conditional_t<std::is_arithmetic_v<T>, typename foo_aux<T>::type, double> 仍会触发相同的错误.

第三次尝试(成功)

template<typename T, bool comp>
struct foo_aux_aux
{
    using type = float;
};
template<typename T>
struct foo_aux_aux<T, true>
{
    using type = int;
};

template<typename T, bool isArithmeticType>
struct foo_aux
{
    using type = double;
};

template<typename T>
struct foo_aux<T, true>
{
    using type = typename foo_aux_aux<T, sizeof(T) < sizeof(void*)>::type;
};
Run Code Online (Sandbox Code Playgroud)

是的,它按预期工作,但它真的很乏味和丑陋.

你有优雅的方式吗?

lll*_*lll 6

在C++ 17中,您可以使用if constexpr进行类型计算.只需将类型包装到虚拟容器中并使用值计算,然后通过检索类型decltype.

struct foo 可以实现如下:

template<class T>
struct type_ {
    using type = T;
};

template<class T>
struct foo {
    auto constexpr static type_impl() {
        if constexpr (std::is_arithmetic<T>{}) {
            if constexpr (sizeof(T) < sizeof(void*)) {
                return type_<int>{};
            } else {
                return type_<float>{};
            }
        } else {
            return type_<double>{};
        }
    }

    using type = typename decltype(type_impl())::type;
};

static_assert(std::is_same<foo<incomplete_type>::type, double>{});
Run Code Online (Sandbox Code Playgroud)


cpp*_*ner 5

如果你换你的第二次尝试的作品doubletype_identity(这是一个标准程序在C++ 20)和移动::typestd::conditional_t<...>:

template<typename T, bool>
struct foo_aux_aux
{
    using type = float;
};
template<typename T>
struct foo_aux_aux<T, true>
{
    using type = int;
};

template<typename T, bool = false>
struct foo_aux : foo_aux_aux<T, sizeof(T) < sizeof(void*)>
{};

template<typename T>
struct type_identity { using type = T; };

typename std::conditional_t<std::is_arithmetic_v<T>, foo_aux<T>, type_identity<double>>::type
Run Code Online (Sandbox Code Playgroud)