jeudi 3 octobre 2019

How to make SFINAE check less verbose?

I have several overloading functions like below:

    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.

So far the code works well but they look quite verbose.

What I want here is what is the neatest way to avoid repetition of checking Point<> type in get/set functions?.

I have tried like these but they do not work:

    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
        }

In MSVC 2019 error C1001: An internal error has occurred in the compiler. error C1001: To work around this problem, try simplifying or changing the program near the locations listed above.

Aucun commentaire:

Enregistrer un commentaire