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)?
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With