Is it possible to check if a user literal is defined for given type and argument?

前端 未结 2 1847
刺人心
刺人心 2021-01-04 09:33

I want to check at compile-time if user literal _name is defined for type Ret and argument Arg. While I have half-solution, it require

相关标签:
2条回答
  • 2021-01-04 09:51

    With is_detected functions family, you may just do

    template <typename T>
    using has_literal_x_type = decltype(operator"" _x(std::declval<T>()));
    
    template <typename Ret, typename T>
    using has_literal_x = std::is_same<Ret, detected_t<has_literal_x_type, T>>;
    

    And test it with

    static_assert(!has_literal_x<one, char const*>::value, "unexpected");
    static_assert(!has_literal_x<one, unsigned long long int>::value, "unexpected");
    static_assert(!has_literal_x<two, char const*>::value, "unexpected");
    static_assert(!has_literal_x<two, unsigned long long int>::value, "unexpected");
    static_assert(!has_literal_x<int, char const*>::value, "unexpected");
    

    Demo

    0 讨论(0)
  • 2021-01-04 09:54

    Is it possible to check if an user literal is defined for given type and argument?

    The (short) answer is yes.


    As an example, you can use the following specialization in your example code:

    template<class T, class S> 
    struct has_literal_x <T, S,
          std::enable_if_t<std::is_same<decltype(operator""_x(std::declval<S>())), T>::value>
        > : std::true_type
    { };
    

    That quickly becomes:

    #include <iostream>
    #include <type_traits>
    #include <utility>
    
    struct one { };
    struct two { };
    
    //one operator"" _x(char const*) { return {}; }
    //two operator"" _x(unsigned long long int) { return {}; }
    
    template<class T, class S, class = void>
    struct has_literal_x : std::false_type
    {  };
    
    template<class T, class S> 
    struct has_literal_x <T, S, 
          std::enable_if_t<std::is_same<decltype(operator""_x(std::declval<S>())), T>::value> 
        > : std::true_type
    { };
    
    int main()
    {  
        std::cout << has_literal_x<one, char const*>::value << std::endl;
        std::cout << has_literal_x<two, unsigned long long int>::value << std::endl;
    
        std::cout << has_literal_x<one, unsigned long long int>::value << std::endl;
        std::cout << has_literal_x<two, char const*>::value << std::endl;
    
        std::cout << has_literal_x<int, char const*>::value << std::endl;
    }
    

    The output is the expected one: 0 for all of them.


    Another way to do that in C++14 (mostly inspired by this answer of @Jarod42) is by means of a template variable.
    As an example:

    template<typename T, typename S, typename = void>
    constexpr bool has_literal_v = false;
    
    template<typename T, typename S>
    constexpr bool has_literal_v<T, S, std::enable_if_t<std::is_same<decltype(operator""_x(std::declval<S>())), T>::value>> = true;
    

    The main would become instead:

    int main()
    {  
        std::cout << has_literal_v<one, char const*> << std::endl;
        std::cout << has_literal_v<two, unsigned long long int> << std::endl;
    
        std::cout << has_literal_v<one, unsigned long long int> << std::endl;
        std::cout << has_literal_v<two, char const*> << std::endl;
    
        std::cout << has_literal_v<int, char const*> << std::endl;
    }
    

    I find it easy to read and that's a constexpr variable. What else?

    0 讨论(0)
提交回复
热议问题