Как создать проверку времени компиляции для нескольких типов C ++? - PullRequest
0 голосов
/ 06 февраля 2019

У меня есть template <class Class> универсальная функция, которая включает в себя:

std::ostringsteam objectStream;

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

return objectStream.str();

Для эффективности я хочу оптимизировать регистр Class строк.

Поэтому я делаюрассылка тегов по шаблонам для перегрузки функции шаблона для каждого элемента 27 - это книга Скотта Майерса «Эффективное современное С ++».

Поэтому мне нужно во время компиляции генерировать std::true_type или std::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 * >()

Я не уверен, как сделать ИЛИ, чтобы компилятор мог отправлять теги при компиляциивремя правильно.

Смежный вопрос, есть ли способ уронить const в const char *, чтобы сделать его char *?

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Мне нравится ответ max66.Простой и элегантный.

Если вам нужно более классическое решение для метафункций (например, что-то вроде check_type_t<T>), и вы не хотите использовать какую-либо библиотеку метапрограммирования, такую ​​как 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 ++ попытается выбрать наиболее специализированный шаблон, поэтому, когда любой из типов, которые вы хотите (например, строка), передается в 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.

Надеюсь, это помогло.

0 голосов
/ 07 февраля 2019

Для вашего первого вопроса:

Если вы используете 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;
}

Демо

Для 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;
}

Демо

ДляВаш второй вопрос: если вы хотите, чтобы обычное удаление const для указателя на const T, вы можете использовать встроенные 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

0 голосов
/ 06 февраля 2019

Поэтому мне нужно сгенерировать во время компиляции либо std::true_type, либо std::false_type.

Учитывая template<class Class>, мне нужно 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>;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...