Как сделать так, чтобы SFINAE проверял меньше слов? - PullRequest
0 голосов
/ 03 октября 2019

У меня есть несколько функций перегрузки, как показано ниже:

    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.

Пока код работает хорошо, но выглядит довольно многословно.

То, что я хочу здесь, это то, что это самый лучший способ избежать повторения проверки типа Point <> в функциях get / set?.

Я пробовал вот так, но они не работают:

    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: Чтобы обойти эту проблему, попробуйте упростить или изменить программу рядом с местами, перечисленными выше.

...