【问题标题】:How to create compile time check for multiple C++ types?如何为多种 C++ 类型创建编译时检查?
【发布时间】:2019-02-06 20:34:26
【问题描述】:

我有一个 template <class Class> 通用函数,其中包括:

std::ostringsteam objectStream;

objectStream << std::forward<Class>(object);

return objectStream.str();

为了效率,我希望优化Class字符串的大小写。

因此,我在模板上进行标签调度以重载模板函数,第 27 条是 Scott Myers 的 Effective Modern C++ book。

因此我需要在编译时生成std::true_type 或std::false_type。

给定一个template&lt;class Class&gt;,如果这些表达式中的任何一个为真,我需要一个std::true_type:

std::is_same<typename std::decay<Class>::type,       char   * >()
std::is_same<typename std::decay<Class>::type, const char   * >()
std::is_same<typename std::decay<Class>::type,       string   >()
std::is_same<typename std::decay<Class>::type,       string * >()
std::is_same<typename std::decay<Class>::type, const string * >()

我不确定如何执行 OR,以便编译器可以在编译时正确调度标签。

相关问题,有没有办法将const 放入const char * 以使其成为char *?

【问题讨论】:

    标签: c++ c++11 templates overriding


    【解决方案1】:

    第一个问题,

    如果您使用的是 c++17,您可以使用折叠表达式在几行中完成此操作

    #include <iostream>
    using namespace std;
    
    template <typename C, typename... Ts> 
    using matches_my_types = std::bool_constant< ( ... | std::is_same<C,Ts>::value)>;
    
    //or with a predefined set of types..
    template <typename C>
    using matches_my_predefined_set_of_types = matches_my_types<C,bool,double,int>;
    
    int main() {
    
        using Class = int; 
        std::cout << matches_my_types<Class,bool,double,int>::value << std::endl;
        std::cout << matches_my_predefined_set_of_types<Class>::value << std::endl;   
        return 0;
    }
    

    Demo

    对于 c++11,您可以执行类似的操作,但使用递归代替折叠。

    #include <iostream>
    using namespace std;
    
    template<typename B, typename...Bs> struct any_true
        : std::conditional_t<bool(B::value), B, any_true<Bs...>>{};
    template<typename B> struct any_true<B> : B {};
    
    template <typename C, typename... Ts> 
    using matches_my_types = any_true<std::is_same<C,Ts>...>;
    
    
    int main() {
    
        using Class = int;
        std::cout << matches_my_types<Class,bool,double,int>::value << std::endl;
        return 0;
    }
    

    Demo

    对于你的第二个问题,如果你想在指向 const T 的指针上通用删除 const,你可以使用内置的 type_traits 和条件,

    #include <iostream>
    #include <typeinfo>
    
    using namespace std;
    
    template <typename T>
    using remove_const_if_pointer_to_const = 
        std::conditional_t<std::is_pointer<T>::value,
            std::add_pointer_t<std::remove_const_t<std::remove_pointer_t<T>>>,
            T>;
    
    int main() {
    
        using A = int;
        using B = int*;
        using C = const int*;
    
        std::cout << typeid(remove_const_if_pointer_to_const<A>).name() << std::endl;
        std::cout << typeid(remove_const_if_pointer_to_const<B>).name() << std::endl;
        std::cout << typeid(remove_const_if_pointer_to_const<C>).name() << std::endl;
    
        return 0;
    }
    

    Demo

    【讨论】:

      【解决方案2】:

      因此我需要在编译时生成std::true_type 或std::false_type。

      给定一个template&lt;class Class&gt;,如果这些表达式中的任何一个为真,我需要一个std::true_type [...]

      记住std::true_type 和std::false_type 分别是别名

      std::integral_constant<bool, true>; // aka std::true_type
      std::integral_constant<bool, false>; // aka std::false_type
      

      如果我理解正确,你想要这个或类似的东西

      using tct = typename std::decay<Class>::type; // to make shorter
      
      using yourType = std::integral_constant<bool, std::is_same<tct, char * >::value
                                                 || std::is_same<tct, const char * >::value
                                                 || std::is_same<tct, string >::value
                                                 || std::is_same<tct, string *>::value
                                                 || std::is_same<tct, const string *>::value>;
      

      相关问题,有没有办法将const 放入const char * 以使其成为char *?

      我想你可以创建一个自定义模板如下

      template <typename T>
      struct foo
       { using type = T; };
      
      template <typename T>
      struct foo<T const *>
       { using type = T *; };
      

      所以你可以将前面的代码简化如下

      using tct = typename std::decay<Class>::type; // to make shorter
      using tft = typename foo<tct>::type
      
      using yourType = std::integral_constant<bool, std::is_same<tft, char * >::value
                                                 || std::is_same<tft, string >::value
                                                 || std::is_same<tft, string *>::value>;
      

      【讨论】:

        【解决方案3】:

        我喜欢 max66 的回答。简洁大方。

        如果您需要更经典的元函数解决方案(例如check_type_t&lt;T&gt;)并且您不想使用任何元编程库,例如boost::mpl 或boost::hana 等...您可以简单地执行以下操作:

        template <class Class, class = void>
        struct check_type_ {
           using type = std::false_type;
        };
        
        template <class Class>
        struct check_type_<Class,
           std::enable_if_t<
              std::is_same<typename std::decay<std::remove_const_t<Class>>::type, char*>::value
        >> {
           using type = std::true_type;
        };
        
        template <class Class>
        struct check_type_<Class,
           std::enable_if_t<
              std::is_same<typename std::decay<std::remove_const_t<Class>>::type, string*>::value
        >> {
           using type = std::true_type;
        };
        template <class Class>
        struct check_type_<Class,
           std::enable_if_t<
              std::is_same<typename std::decay<Class>::type, string>::value
        >> {
           using type = std::true_type;
        };
        
        template <class Class>
        using check_type_t = typename check_type_<Class>::type;
        
        static_assert(std::is_same<check_type_t<char*>, std::true_type>::value, "");
        static_assert(!std::is_same<check_type_t<int>, std::true_type>::value, "");
        

        C++ 将尝试选择最专业的模板,因此当您想要的任何类型(例如字符串)被传递给 check_type_t&lt;&gt; 中的 Class 时,

        std::enable_if_t<
           std::is_same<typename std::decay<Class>::type, string>::value
        >
        

        没有形成错误并导致void。所以选择了这个专业化,里面的类型是std::true_type。如果没有一个专业化格式正确,则选择主模板,结果为std::false_type。

        希望对你有帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-06
          • 2014-03-31
          • 2012-06-10
          • 2020-02-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多