2
votes

Comment créer un contrôle de temps de compilation pour plusieurs types C ++?

J'ai une fonction générique template qui inclut:

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

Pour plus d'efficacité, je souhaite optimiser le cas de Class code> strings.

Par conséquent, je suis en train de distribuer des balises sur des modèles pour surcharger la fonction de modèle par élément 27 est le livre Effective Modern C ++ de Scott Myers.

Par conséquent, je dois générer au moment de la compilation, soit un std :: true_type soit un std::false_type.

Étant donné un template , J'ai besoin d'un std :: true_type si l'une de ces expressions est vraie:

std::ostringsteam objectStream;

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

return objectStream.str();

Je ne sais pas comment faire le OU alors le le compilateur peut distribuer correctement les balises au moment de la compilation.

Question connexe, y a-t-il un moyen de déposer le const dans un const char * pour faire il char * ?


0 commentaires

3 Réponses :


2
votes

Par conséquent, je dois générer au moment de la compilation un std :: true_type ou std :: false_type .

Étant donné un template , j'ai besoin d'un std :: true_type si l'une de ces expressions est vraie [...]

En se rappelant que std :: true_type et std :: false_type sont respectivement des alias pour

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

si Je comprends bien, vous voulez ceci ou quelque chose de similaire

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

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

Question connexe, y a-t-il un moyen de déposer le const dans un const char * pour le rendre char * ?

Je suppose que vous pouvez créer un modèle personnalisé comme suit

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

Vous pouvez donc simplifier le code précédent comme suit

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

0 commentaires

0
votes

J'aime la réponse de max66. Simple et élégant.

Si vous avez besoin d'une solution de métafonction plus classique (c'est-à-dire quelque chose comme check_type_t ) et que vous ne voulez pas utiliser de bibliothèque de méta-programmation comme boost: : mpl ou boost :: hana etc ... Vous pouvez simplement faire ce qui suit:

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

C ++ essaiera de sélectionner le le modèle le plus spécialisé, donc lorsque l'un des types que vous souhaitez (par exemple, une chaîne) est passé à Class dans check_type_t , alors le

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, "");


0 commentaires

2
votes

Pour votre première question,

Si vous utilisez c ++ 17, vous pouvez le faire en quelques lignes en utilisant une expression de repli

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

Démo

Pour c ++ 11, vous pouvez faire quelque chose de similaire, mais en utilisant la récursivité à la place de le pli.

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

Démo

Pour votre deuxième question, si vous voulez une suppression générale de const sur le pointeur vers const T, vous pouvez utiliser le type_traits intégré et le conditionnel,

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

Démo


0 commentaires