如何让 SFINAE 检查不那么冗长?

问题描述 投票:0回答:1

我有几个重载函数,如下所示:

    template<typename T>
    struct Point {
        std::enable_if_t<std::is_arithmetic_v<T>, T>
            x, y;
    };


    // These are two functions accepting only Point<> type.

    template <typename T>
    std::enable_if_t < std::is_class_v<T>
        && std::is_arithmetic_v<decltype(T::x)>
        && std::is_arithmetic_v<decltype(T::y)>
        && sizeof(T) == sizeof(decltype(T::x)) + sizeof(decltype(T::y)), T>
        get(const char* key, T defaultValue)
    {
        //  do something ..
        return defaultValue;
    }

    template <typename T>
    void set(const char* key, std::enable_if_t < std::is_class_v<T>
        && std::is_arithmetic_v<decltype(T::x)>
        && std::is_arithmetic_v<decltype(T::y)>
        && sizeof(T) == sizeof(decltype(T::x)) + sizeof(decltype(T::y)), T> value)
    {
        //  do something ..
    }

    template <typename T>
    std::enable_if_t <std::is_arithmetic_v<T>, T>
    get(const char* key, T defaultValue)
    {
        return defaultValue;
    }

    template <typename T>
    std::enable_if_t <std::is_enum_v<T>, T>
    get(const char* key, T defaultValue)
    {
        return defaultValue;
    }

    // There are others overloading get<>(), set<>() for other types.


    // Then call them
    auto pod1 = get<int>(key, {});// OK
    auto pod2 = get<float>(key, {});// OK
    auto enm = get<SomeEnum>(key, {});// OK
    auto pt1 = get<Point<int>>(key, {}); // OK
    auto pt2 = get<Point<std::string>>(key, {}); // failed - correctly.

到目前为止,代码运行良好,但看起来相当冗长。

我想要的是避免在 get/set 函数中重复检查 Point<> 类型的最巧妙方法是什么?。

我已经尝试过这些,但它们不起作用:

    template <typename T>
    using is_point_t = std::enable_if_t <
        std::is_class_v<T>
        && std::is_arithmetic_v<decltype(T::x)>
        && std::is_arithmetic_v<decltype(T::y)>
        && (sizeof(T) == sizeof(decltype(T::x)) + sizeof(decltype(T::y))), T>;


    template <typename T>
    is_point_t<T>
    get(const char* key, T defaultValue)
    {
        // do something
        return defaultValue;
    }

    template <typename T>
    void set(const char* key, is_point_t<T> value)
    {
    // do something
    }


    //   Or even like this, it also fails

    template <typename T>
    inline constexpr bool is_point_v = std::is_class_v<T>
        && std::is_arithmetic_v<decltype(T::x)> 
        && std::is_arithmetic_v<decltype(T::y)>
        && (sizeof(T) == sizeof(decltype(T::x)) + sizeof(decltype(T::y)));

    template <typename T>
    std::enable_if_t <is_point_v<T>, T>
        get(const char* key, T defaultValue) 
        {
            // do something
            return defaultValue;
        }

    template <typename T>
        void set(const char* key, 
        std::enable_if_t <is_point_v<T>, T> value) 
        {
            // do something
        }

MSVC 2019 错误 C1001:编译器中发生内部错误。 错误 C1001:要解决此问题,请尝试简化或更改上面列出的位置附近的程序。

c++11 visual-c++ c++14 sfinae
1个回答
0
投票

它不起作用,因为如果类型

T
不包含成员属性
x
y
,编译会失败。要创建
is_point
类型特征(如果满足上述所有条件则为真),有必要利用 SFINAE。

namespace detail {
  template <typename, bool = true>
  struct is_point
   : std::false_type {};

  template <typename T>
  struct is_point<T, std::is_class_v<T>
   && std::is_arithmetic_v<decltype(T::x)>
   && std::is_arithmetic_v<decltype(T::y)>
   && (sizeof(T) == sizeof(decltype(T::x)) + sizeof(decltype(T::y)))>
  : std::true_type {};
}

template <typename T>
struct is_point
 : detail::is_point<T> {};

template <typename T>
inline constexpr bool is_point_v = is_point<T>::value;
© www.soinside.com 2019 - 2024. All rights reserved.