简体   繁体   English

如何为多种C ++类型创建编译时检查?

[英]How to create compile time check for multiple C++ types?

I have a template <class Class> generic function that includes: 我有一个template <class Class>泛型函数,包括:

std::ostringsteam objectStream;

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

return objectStream.str();

For efficiency, I wish to optimize the case of Class strings. 为了提高效率,我希望优化Class字符串的大小写。

Therefore, I'm doing tags dispatch on templates for overloading the template function per item 27 is Scott Myers' Effective Modern C++ book. 因此,我正在为模板分配标签,以使每项27的模板功能过载,这是Scott Myers的《 Effective Modern C ++》一书。

Therefore I need to generate at compile time either a std::true_type or std::false_type . 因此,我需要在编译时生成std::true_typestd::false_type

Given a template<class Class> , I need a std::true_type if any of these expressions are true: 给定template<class Class> ,如果以下任何表达式为真,则需要一个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 * >()

I'm not sure how to do the OR so the compiler can dispatch on the tags at compile time correctly. 我不确定如何执行“或”操作,以便编译器可以在编译时正确分派标签。

Related question, is there a way to drop the const in a const char * to make it char * ? 相关问题,是否有办法将const放入const char *以使其成为char *

Therefore I need to generate at compile time either a std::true_type or std::false_type . 因此,我需要在编译时生成std::true_typestd::false_type

Given a template<class Class> , I need a std::true_type if any of these expressions are true [...] 给定一个template<class Class> ,如果这些表达式中的任何一个为真,我就需要一个std::true_type [...]

Remembering that std::true_type and std::false_type are alias, respectively, for 记住std::true_typestd::false_type分别是别名

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

if I understand correctly, you want this or something similar 如果我理解正确,您想要这个或类似的东西

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>;

Related question, is there a way to drop the const in a const char * to make it char * ? 相关问题,是否有办法将const放入const char *以使其成为char *

I suppose you can create a custom template as follows 我想您可以如下创建自定义模板

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

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

So you can simplify the preceding code as follows 这样您就可以简化前面的代码,如下所示

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>;

For your first question, 对于第一个问题,

If you're using c++17 you can do this in a few lines using a fold expression 如果您使用的是c ++ 17,则可以使用fold表达式在几行中完成此操作

#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 演示

For c++11 you can do something similar, but using recursion in place of the fold. 对于c ++ 11,您可以执行类似的操作,但是使用递归代替fold。

#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 演示

For your second question, if you want a general remove const on pointer to const T, you can use the built in type_traits and conditional, 对于第二个问题,如果要在指向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 演示

I like max66's answer. 我喜欢max66的答案。 Simple and elegant. 简洁大方。

If you need a more classic metafunction solution (ie something like check_type_t<T> ) and you don't want to use any meta-programming library like boost::mpl or boost::hana etc... You can simply do the following: 如果您需要更经典的元函数解决方案(例如,诸如check_type_t<T>类的东西),并且您不想使用诸如boost::mplboost::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++ will try to select the most specialized template so when any of the type you want(for example string) is passed to Class in check_type_t<> then the C ++会尝试选择最专业的模板,以便在check_type_t<>中将check_type_t<>任何类型(例如字符串)传递给Class时,

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

is not ill formed and resulting to void . 没有病态形成并导致void So this specialization is selected and the type inside is std::true_type . 因此选择了此专业化,并且内部类型为std::true_type If none of the specializations is well formed then the main template is selected and the result is std::false_type . 如果没有一个专业std::false_type良好,则选择主模板,结果为std::false_type

I hope it helped. 希望对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM