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

倾然丶 夕夏残阳落幕 提交于 2019-11-30 01:51:24

问题


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 requires the literal operator to be defined at least once:

#include <iostream>
#include <type_traits>

struct one { };
struct two { };

// we need at least one of these definitions for template below to compile
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::void_t<decltype((T(*)(S))(operator"" _x))>
    > : 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;
}

Output:

1
1
0
0
0

But if there isn't at least one definition of possibly overloaded user literal, this solution will not work. Is there any way to check it even for non-existing literals (possibly the same way we can check if class X has member member, but I don't know if it's viable in this case)?


回答1:


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?




回答2:


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



来源:https://stackoverflow.com/questions/39725067/is-it-possible-to-check-if-a-user-literal-is-defined-for-given-type-and-argument

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!