2016-03-28 1 views
4

Étant donné:Déterminer le plus grand sizeof() en boost variante

boost::variant<T1,T2,T3,...,TN> 

Calculer les éléments suivants au moment de la compilation:

max(sizeof(T1), sizeof(T2), sizeof(T3),... ,sizeof(TN)) 

Je ne savais pas comment aborder, mais this réponse à jeter un peu de lumière sur comment je pourrais commencer. En utilisant le code dans cette réponse avec deux types, T1 et T2, je pourrais utiliser ce qui suit dans un fichier source pour obtenir la taille de l'objet plus grand:

size_t largestSize = sizeof(largest<T1, T2>::type); 

C'est exactement ce que je voudrais faire, mais j'ai besoin du modèle largest pour travailler avec plus de deux classes - en particulier, il faudrait vérifier tous les types stockés dans un objet boost::variant.

Je sais que boost::variant a un typedef types, qui définit une sorte de liste de types dans la variante. Le problème est, je suis totalement perdu quand j'essaie d'enrouler ma tête autour de toutes les choses dans l'implémentation. Je ne comprends pas intuitivement ce boost::variant::typesest, et comment je pourrais être en mesure de le transmettre dans mon propre modèle qui fait quelque chose avec elle.

Dans ma tête, c'est ce que la mise en œuvre finale pourrait ressembler à:

typedef boost::variant<T1, T2, T3, T4> MyVariant; 
size_t largestSize = sizeof(largest<MyVariant::types>::type); 

Malheureusement, je ne sais pas comment aller sur l'implémentation de cette version de largest. Je ne suis pas sûr si c'est une approche raisonnable, donc je suis ouvert à d'autres façons d'accomplir cela (peut-être appliquer un boost::static_visitor à tous les types au moment de la compilation?).

Répondre

7

Ignorez simplement les trucs mpl. Commencez par:

template <class T> struct max_variant_sizeof; 

template <class... Ts> 
struct max_variant_sizeof<boost::variant<Ts...>> { 
    static constexpr size_t value = variadic_max(sizeof(Ts)...); 
}; 

maintenant max_variant_sizeof<MyVariant>::value transmettra toutes les tailles de tous les types de fonction. Tout ce que vous devez faire est d'écrire que variadic_max:

constexpr size_t variadic_max(size_t v) { return v; } 

template <class... Args> 
constexpr size_t variadic_max(size_t a, size_t b, Args... cs) 
{ 
    return variadic_max(std::max(a, b), cs...); 
} 

Avant C++ 14, std::max() n'est pas constexpr, de sorte que peut être remplacé par:

return variadic_max((a > b ? a : b), cs...); 

Une chose à noter environ:

peut appliquer un boost::static_visitor à tous les types au moment de la compilation?

Visitation avec un variant est une exécution opération - le visiteur est appelé avec le type que le variant arrive à tenir sur. Il ne sera pas appelé avec tous les types.

+0

Je suis allé avec cette solution, mais pendant mes tests, j'ai remarqué que ce ne sera pas compilé avec GCC 4.8.2 ou 3.5.0 et plus clang , tandis que la réponse de Wojciech ci-dessous se compile avec GCC 4.7.3 et clang 3.0. J'ai également remarqué qu'aucune des deux solutions ne compilait avec MSVC19. Rien de tout cela n'a d'importance dans le contexte de la question, mais cela pourrait être utile pour quelqu'un qui trébuche sur cette réponse. –

2

Vous pouvez également modifier le code du lien que vous avez attaché à:

template <class First, class... Args> 
struct largest: largest<First, typename largest<Args...>::type> { 
}; 

template<bool, typename T1, typename T2> 
struct is_cond { 
    typedef T1 type; 
}; 

template<typename T1, typename T2> 
struct is_cond<false, T1, T2> { 
    typedef T2 type; 
}; 

template<typename T1, typename T2> 
struct largest<T1, T2> { 
    typedef typename is_cond< (sizeof(T1)>sizeof(T2)), T1, T2>::type type; 
}; 

Ensuite, l'utilisation pourrait ressembler à:

cout << sizeof(largest<int, char, double>::type) << endl; 

Edit:

Pour le faire fonctionner avec boost :: variant ainsi que n'importe quelle autre classe de template args variadique ajoutez juste une autre spécialisation:

template <template <class...> class Var, class... Args> 
struct largest<Var<Args...>>: largest<Args...> { }; 

Ensuite, l'utilisation pourrait ressembler, par ex. (Avec tuple, qui peut être changé avec succès pour stimuler :: variante):

cout << sizeof(largest<tuple<int, char, double>>::type) << endl; 
1

j'utiliser la bibliothèque boost::mpl comme une bibliothèque générique pour les opérations de code de compilation.

Certains préparation de code d'en-tête:

#include <boost/mpl/vector.hpp> 
#include <boost/mpl/max_element.hpp> 
#include <boost/mpl/transform_view.hpp> 
#include <boost/mpl/sizeof.hpp> 

#include <boost/type_traits/alignment_of.hpp> 

// alignof_ headers 
#include <boost/mpl/size_t.hpp> 
#include <boost/mpl/aux_/na_spec.hpp> 
#include <boost/mpl/aux_/lambda_support.hpp> 

// alignof mpl style implementation (namespace injection) the same way as the `mpl::sizeof_` did 
namespace boost { 
namespace mpl { 
    template< 
     typename BOOST_MPL_AUX_NA_PARAM(T) 
    > 
    struct alignof_ 
     : mpl::size_t< boost::alignment_of<T>::value > 
    { 
     BOOST_MPL_AUX_LAMBDA_SUPPORT(1, alignof_, (T)) 
    }; 

    BOOST_MPL_AUX_NA_SPEC_NO_ETI(1, alignof_) 
} 
} 

'

Certains macro aide:

// generates compilation error and shows real type name (and place of declaration in some cases) in an error message, useful for debugging boost::mpl recurrent types 

// old C++ standard compatible 
//#define UTILITY_TYPE_LOOKUP_BY_ERROR(type_name) \ 
// (*(::utility::type_lookup<type_name >::type*)0).operator ,(*(::utility::dummy*)0) 

// can be applied in a class, but requires `decltype` support 
#define UTILITY_TYPE_LOOKUP_BY_ERROR(type_name) \ 
    typedef decltype((*(::utility::type_lookup<type_name >::type*)0).operator ,(*(::utility::dummy*)0)) _type_lookup_t 

namespace utility 
{ 
    struct dummy {}; 

    template <typename T> 
    struct type_lookup 
    { 
     typedef T type; 
    }; 
} 

'

Exemple d'utilisation:

namespace mpl = bost::mpl; 

typedef mpl::vector<T1, T2, T3, T4, T5> storage_types_t; 

typedef typename mpl::deref< 
    typename mpl::max_element< 
     mpl::transform_view<storage_types_t, mpl::sizeof_<mpl::_1> > 
    >::type 
>::type max_size_t; // type has stored max sizeof(T1, T2, T3, T4, T5) 

typedef typename mpl::deref< 
    typename mpl::max_element< 
     mpl::transform_view<storage_types_t, mpl::alignof_<mpl::_1> > 
    >::type 
>::type max_alignment_t; // type has stored max alignof(T1, T2, T3, T4, T5) 

// testing on real values 
UTILITY_TYPE_LOOKUP_BY_ERROR(max_size_t); 
UTILITY_TYPE_LOOKUP_BY_ERROR(max_alignment_t); 

'

Visual Studio 2015 Sortie d'erreur:

 
error C2039: ',': is not a member of 'boost::mpl::size_t<**calculated max sizeof here**>' 
error C2039: ',': is not a member of 'boost::mpl::size_t<**calculated max alignment here**>'