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

问题描述 投票:2回答:3

我有一个template <class Class>通用功能,包括:

std::ostringsteam objectStream;

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

return objectStream.str();

为了提高效率,我希望优化Class字符串的情况。

因此,我正在做模板上的标签调度,以便按项目重载模板功能27是Scott Myers的Effective Modern C ++书。

因此,我需要在编译时生成std::true_typestd::false_type

鉴于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 * >()

我不确定如何执行OR,因此编译器可以在编译时正确地在标记上进行调度。

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

c++ c++11 templates override tag-dispatch
3个回答
2
投票

对于你的第一个问题,

如果你使用的是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

对于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和conditional,

#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_typestd::false_type

给定template<class Class>,如果这些表达式中的任何一个是真的,我需要一个std::true_type [...]

记住std::true_typestd::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>;

0
投票

我喜欢max66的答案。简单而优雅。

如果你需要一个更经典的元函数解决方案(比如像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 ++将尝试选择最专业的模板,这样当你想要的任何类型(例如字符串)传递给Class中的check_type_t<>时,

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

没有生病,导致void。所以选择了这个专业化,里面的类型是std::true_type。如果没有完成任何专业化,则选择主模板,结果为std::false_type

我希望它有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.