【问题标题】:How implement SFINAE limited to few types, using template parameter pack如何使用模板参数包实现 SFINAE 仅限于少数类型
【发布时间】:2020-05-30 00:35:17
【问题描述】:

我需要启用 std::string 和 int,但使用参数包。

template <typename... ParamType, typename = typename std::enable_if<std::is_same<ParamType..., std::string>::value || std::is_same<ParamType..., int>::value>::type>
static inline void Log(const ParamType & ... args)
{

}

但我打电话时出错

Log("hello"s, "world"s); //syntax ERROR 

想要的结果

Log(4,3,"Hello"s); //OK
Log("Hello"s); //OK
Log(5); //OK

【问题讨论】:

    标签: c++ visual-c++ c++17


    【解决方案1】:

    这个解决方案使用了一些 C++17-ism (std::void_t)。如果需要,它们的各种实现适用于随处可见的早期 C++ 标准:

    template <typename ... ParamType,
          typename = std::void_t<std::enable_if_t
                     <std::is_same_v<ParamType, std::string> ||
                      std::is_same_v<ParamType, int>>...>>
    static inline void Log(const ParamType & ... args)
    {
    
    }
    

    【讨论】:

    • std::void_t 简单但有效的拼写。谢谢。
    【解决方案2】:

    你想要(is_string_or_int(param_0)) &amp;&amp; (is_string_or_int(param_1)) &amp;&amp; (is_string_or_int(param_2)) &amp;&amp; ...。这可以用 fold 表达式来写:

    typename std::enable_if<
        (true && ... && (
            std::is_same<ParamType, std::string>::value ||
            std::is_same<ParamType, int>::value
        ))
    >::type
    

    这仅适用于 C++17 及更高版本。对于 C++11 友好的解决方案,您可以使用 struct 特化来迭代类型:

    // true iff Testing is any of Required...
    template<typename Testing, typename... Required>
    struct one_match : std::false_type {};
    
    template<typename Testing, typename First, typename... Rest>
    struct one_match<Testing, First, Rest...> : std::bool_constant<std::is_same<Testing, First>::value || one_match<Testing, Rest...>::value> {};
    
    // true iff all of TestingTypes... are in the tuple RequiredTypesTuple
    template<typename RequiredTypesTuple, typename... TestingTypes>
    struct all_match;
    
    template<typename... RequiredTypes>
    struct all_match<std::tuple<RequiredTypes...>> : std::true_type {};
    
    template<typename... RequiredTypes, typename First, typename... Rest>
    struct all_match<std::tuple<RequiredTypes...>, First, Rest...> : std::bool_constant<one_match<First, RequiredTypes...>::value && all_match<std::tuple<RequiredTypes...>, Rest...>::value> {};
    
    
    template <typename... ParamType, typename enabler =
    typename std::enable_if<
        all_match<std::tuple<std::string, int>, ParamType...>::value
    >::type>
    static inline void Log(const ParamType & ... args)
    {
    
    }
    

    【讨论】:

      【解决方案3】:

      中使用折叠表达式:

      #include <type_traits>
      
      template <typename... ParamType>
      static inline auto Log(const ParamType&... args)
          -> std::enable_if_t<((std::is_same_v<ParamType, std::string>
                             || std::is_same_v<ParamType, int>) && ...)>
      {
      }
      

      但是,如果没有替代的 Log 重载可用于不满足条件的参数,请考虑使用 static_assert 来提供信息性错误消息:

      template <typename... ParamType>
      static inline void Log(const ParamType&... args)
      {
          static_assert(((std::is_same_v<ParamType, std::string>
                       || std::is_same_v<ParamType, int>) && ...)
                        , "Only ints and strings");
      }
      

      中使用概念:

      #include <type_traits>
      
      template <typename T>
      concept LogParam = std::is_same_v<T, std::string> || std::is_same_v<T, int>;
      
      static inline void Log(const LogParam auto&... args)
      {
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-15
        • 1970-01-01
        • 2016-11-26
        相关资源
        最近更新 更多