2016-03-28 4 views
4

Дано:Определение, большой SizeOf() в варианте повышающего

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

Рассчитайте следующие во время компиляции:

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

Я не имел ни малейшего представления о том, как подойти к этому, но this ответ пролить некоторый свет на как я могу начать. Использование кода в том, что ответ с двумя типами, T1 и T2, я мог бы использовать следующие в исходном файле, чтобы получить размер крупного объекта:

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

Это именно то, что я хотел бы сделать, но мне нужен шаблон largest для работы с более чем двумя классами - в частности, ему нужно будет проверить все типы, хранящиеся в объекте boost::variant.

Я знаю, что boost::variant имеет types typedef, который определяет какой-то список типов в варианте. Проблема в том, что я полностью теряюсь, когда пытаюсь обернуть голову вокруг всех вещей в реализации. Я не интуитивно понимаю, что boost::variant::typesis, и как я могу передать его в свой собственный шаблон, который что-то с ним делает.

В моей голове, это то, что окончательная реализация может выглядеть следующим образом:

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

К сожалению, я не имею ни малейшего представления о том, как идти о реализации этой версии largest.

Я не уверен, что это разумный подход, поэтому я открыт для любых других способов достижения этого (возможно, примените boost::static_visitor ко всем типам во время компиляции?).

ответ

7

Просто игнорируйте материал mpl. Начать с:

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

Теперь max_variant_sizeof<MyVariant>::value направим все размеры всех типов в функции. Все, что вам нужно сделать, это написать, что 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...); 
} 

Перед C++ 14, std::max() не constexpr, так что можно заменить:

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

Одна вещь стоит отметить около:

Возможно, примените boost::static_visitor ко всем типам во время компиляции?

Visitation с variant является выполнения операция - ваш посетитель вызывается с типом, что variant случается, держась. Он не будет называться с всеми типами.

+0

Я пошел с этим решением, но во время моего тестирования я заметил, что это не будет скомпилирован с GCC 4.8.2 или 3.5.0 лязгом и старше , в то время как ответ Войцеха ниже компилируется с GCC 4.7.3 и clang 3.0. Я также заметил, что ни одно решение не компилируется с MSVC19. Ничего из этого не имеет значения в контексте вопроса, но может быть полезно, если кто-то споткнется об этом ответе. –

2

Вы также можете изменить код по ссылке вы прикреплены к:

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

Тогда использование может выглядеть следующим образом:

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

Edit:

Чтобы сделать его работу с boost :: variant, а также с любым другим вариационным шаблоном шаблонов args просто добавьте еще одну специализацию:

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

Тогда использование может выглядеть, например. (С кортежем, который может быть успешно изменен для увеличения :: варианта):

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

Я используя boost::mpl библиотеки в качестве родовых библиотек для операций во время компиляции коды.

некоторая подготовка кода заголовка:

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

'

Некоторые помощник макро:

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

' пример

Использование:

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 Выход ошибки:

 
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**>' 
Смежные вопросы