2016-09-27 70 views
12

我想在编译时检查用户字面量_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一样,但我不知道在这种情况下它是否可行)?

回答

9

是否可以检查用户文本是否定义给定的类型和参数?

(简)回答是


举个例子,你可以使用下面的专业化在您的示例代码:

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变量。还有什么?

+0

注意测试一下这个解决方案确实,如果经营者类型之后定义不太工作特征至少在GCC中定义:http://coliru.stacked-crooked.com/a/6f70eb6cbf236473 – xinaiz

5

随着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"); 

Demo

+1

不应该是'std :: declval ()'而不是'std :: declval '? – skypjack

+1

@skypjack:当然,修正,谢谢。我不想在Demo中添加有效的情况,因为OP预计操作员可能不会出现,所以我错过了那个错字... – Jarod42

+1

嗯,这是野兽!一般而言,这是一个很好的解决方案,但我期望任何可行的解决方案,而skypjack这次是第一次,而且通常使用已知的语法:)虽然'is_detected'会成为“如何简化复杂的SFINAE语法”这个问题的优胜者。 – xinaiz

相关问题