代码之家  ›  专栏  ›  技术社区  ›  Chen Li

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

  •  5
  • Chen Li  · 技术社区  · 6 年前

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

    foo<incomplete_type> f; incomplete_type 不是算术类型(从逻辑上讲,它不会进入分支的sizeof)。 live demo

    所以,我想 推迟 sizeof :

    第一次尝试(失败)

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

    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*)>
    {};
    

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

    Yes, it works as expected ,但它真的很乏味和丑陋。

    5 回复  |  直到 6 年前
        1
  •  6
  •   llllllllll    6 年前

    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>{});
    
        2
  •  5
  •   cpplearner    6 年前

    你的第二次尝试有效,如果你包装 double 在里面 type_identity (这是 a standard utility 在C++20中)和移动 ::type std::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
    
        3
  •  4
  •   llllllllll    6 年前

    decltype() 和声明(仅)某些函数。

    我的意思是

    struct incomplete_type;
    
    constexpr float baz (std::false_type);
    constexpr int baz (std::true_type);
    
    template <typename>
    constexpr double bar (std::false_type);
    
    template <typename T>
    constexpr auto bar (std::true_type)
     -> decltype(baz<std::bool_constant<(sizeof(T) < sizeof(void*))>{});
    
    template<typename T>
    struct foo
     { using type = decltype( bar<T>(std::is_arithmetic<T>{}) ); };
    
        4
  •  3
  •   felix    6 年前

    您也可以使用SFINAE:

    template <class T1, class T2, class = int (*)[sizeof(T1) < sizeof(T2)]>
    constexpr bool DeferSizeof(int) {
      return true;
    }
    template <class, class>
    constexpr bool DeferSizeof(...) {
      return false;
    }
    
    template<typename T>
    struct foo
    {
        using type = std::conditional_t<std::is_arithmetic_v<T>,
            std::conditional_t<DeferSizeof<T, void *>(0), int, float>,
            double>;
    };
    
        5
  •  2
  •   Piotr Skotnicki    6 年前

    detection idiom 从TS库基础知识v2:

    template <typename T>
    using size_of = std::integral_constant<std::size_t, sizeof(T)>;
    
    template <typename T>
    struct foo
    {
        using type = std::conditional_t<
            std::is_arithmetic_v<T>,
            std::conditional_t<
                std::experimental::detected_or_t<
                    std::integral_constant<std::size_t, 0>, size_of, T
                >{} < sizeof(void*),
                int, float>,
            double>;
    };
    

    DEMO