【问题标题】:Is it possible to check if a user literal is defined for given type and argument?是否可以检查是否为给定类型和参数定义了用户文字?
【发布时间】:2016-09-27 12:44:58
【问题描述】:

我想在编译时检查是否为类型 Ret 和参数 Arg 定义了用户文字 _name。虽然我有一半的解决方案,但它需要至少定义一次文字 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 的方法相同,但我不知道在这种情况下它是否可行)?

【问题讨论】:

    标签: c++ templates sfinae c++17


    【解决方案1】:

    是否可以检查是否为给定类型和参数定义了用户文字?

    (简短的)答案是是的


    例如,您可以在示例代码中使用以下特化:

    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 中执行此操作的另一种方法(主要受 @Jarod42 的 this 答案的启发)是通过模板变量。
    举个例子:

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

    【讨论】:

    【解决方案2】:

    使用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

    【讨论】:

    • 不应该是std::declval&lt;T&gt;()而不是std::declval&lt;T&gt;吗?
    • @skypjack:当然,已修复,谢谢。我不想在 Demo 中添加有效案例,因为 OP 预计操作员可能不会出现,所以我错过了那个错字...
    • 好吧,这是野兽!一般而言,这是一个很好的解决方案,但我期待任何可行的解决方案,这次 skypjack 是第一个并且使用众所周知的语法:) 尽管is_detected 将成为问题“如何简化复杂的 SFINAE 语法”的获胜者。
    • @BlackMoses 我使用基于模板变量的解决方案在我的答案中添加了另一个 sn-p,该解决方案主要受此启发。我可以参加“如何简化复杂的 SFINAE 语法”问题的获胜者比赛吗? :-)
    猜你喜欢
    • 2018-06-08
    • 2021-10-03
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    相关资源
    最近更新 更多