是否有可能检查用户文本是否为给定的类型和参数定义?
问题描述:
我想在编译时检查用户字面量_name
的定义是否为Ret
和参数Arg
。虽然我有一半的解决方案,它要求的字面operator
被至少一次定义:是否有可能检查用户文本是否为给定的类型和参数定义?
#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;
}
输出:
1
1
0
0
0
但是,如果有可能不重载用户文字中的至少一个定义,这个解决方案将不起作用。是否有任何方法可以检查它,即使是不存在的文字(可能与我们可以检查类X
是否有成员member
一样,但我不知道在这种情况下它是否可行)?
答
是否可以检查用户文本是否定义给定的类型和参数?
(简)回答是是。
举个例子,你可以使用下面的专业化在您的示例代码:
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
{ };
,迅速变为:
#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;
}
输出的预期之一:0
所有其中。
另一种方法是,在C++ 14(主要是由this答案@ Jarod42的启发)是由一个模板变量的装置。
作为一个例子:
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;
的main
将成为代替:
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;
}
我发现很容易阅读,这是一个constexpr
变量。还有什么?
答
随着is_detected
功能的家庭,你可能只是做
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>>;
而且随着
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");
注意测试一下这个解决方案确实,如果经营者类型之后定义不太工作特征至少在GCC中定义:http://coliru.stacked-crooked.com/a/6f70eb6cbf236473 – xinaiz