2016-03-28 20 views
4

Gegeben:größte sizeof Bestimmung() im Boost-Variante

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

folgenden bei der Kompilierung ermitteln:

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

ich keine Ahnung hatte, wie man diesen Ansatz, aber this Antwort Schuppen auf etwas Licht wie ich anfangen könnte. Verwenden Sie den Code in dieser Antwort mit zwei Typen, T1 und T2, ich folgend in einer Quelldatei verwenden, könnte die Größe des größeren Objekts zu erhalten:

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

Das ist genau das, was ich tun mag, aber ich brauche die Vorlage largest, um mit mehr als zwei Klassen zu arbeiten - speziell würde es alle Typen überprüfen müssen, die in einem boost::variant Objekt gespeichert werden.

Ich weiß, dass boost::variant eine types typedef hat, die eine Art Liste von Typen in der Variante definiert. Das Problem ist, ich werde total verloren, wenn ich versuche, meinen Kopf um alle boost::mpl Sachen in der Implementierung zu wickeln. Ich verstehe nicht intuitiv, was boost::variant::types ist, und wie ich es in meine eigene Vorlage übergeben könnte, die etwas damit macht.

In meinem Kopf ist es das, was die endgültige Umsetzung aussehen könnte:

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

Leider habe ich keine Ahnung, wie man über die Umsetzung dieser Version von largest zu gehen.

Ich bin nicht sicher, ob dies ein vernünftiger Ansatz ist, also bin ich offen für alle anderen Möglichkeiten, dies zu erreichen (vielleicht eine boost::static_visitor auf alle Arten zur Kompilierzeit anwenden?).

Antwort

7

ignorieren Sie einfach die MPL Zeug. Beginnen Sie mit:

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)...); 
}; 

Jetzt max_variant_sizeof<MyVariant>::value alle Größen aller Typen an eine Funktion weiterleitet. Alles, was Sie tun müssen, ist zu schreiben, dass 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...); 
} 

Vor C 14, ist std::max() ++ nicht constexpr kann, so dass mit Fassung:

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

Eine Sache, erwähnenswert, etwa:

vielleicht eine boost::static_visitor auf alle Arten zur Kompilierzeit anwenden?

Visitation mit einem variant ist ein Laufzeit Betrieb - Ihr Besucher wird mit der Art genannt, dass die variant zu halten werden passiert. Es wird nicht mit alle die Typen aufgerufen.

+0

ich mit dieser Lösung ging, aber während meiner Prüfung bemerkte ich, dass dies mit GCC nicht 4.8.2 oder Klirren 3.5.0 kompiliert und älter , während Wojciechs Antwort unten mit GCC 4.7.3 und clang 3.0 kompiliert. Ich habe auch festgestellt, dass keine Lösung mit MSVC19 kompiliert. Nichts davon ist im Kontext der Frage wirklich wichtig, aber es könnte nützlich sein, wenn jemand über diese Antwort stolpert. –

2

Sie können auch den Code aus dem Link ändern Sie an:

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

Dann könnte die Verwendung wie folgt aussehen:

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

Edit:

es funktioniert mit boost :: variant sowie jeder anderen variadic args templated class fügen Sie einfach eine weitere Spezialisierung hinzu:

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

Dann könnte die Verwendung z.B. (Mit Tupel, die erfolgreich geändert werden kann, um boost :: Variante):

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

Ich habe mit der boost::mpl Bibliothek als eine generische Bibliothek für die Kompilierung Codeoperationen.

Einige Header-Code Zubereitung:

#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_) 
} 
} 

'

Einige Helfer Makro:

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

'

Anwendungsbeispiel:

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 Fehlerausgabe:

 
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**>'