Опитах се да напиша функция, която ми позволява да конструирам boost::variant<>
от пакет с параметри. С други думи, опитвам се да конструирам един от типа boost::variant<>::types
, чийто подпис на конструктора съответства на пакета, и след това да конвертирам в boost::variant<>
. Наивно написах следното:
#!/usr/bin/env sh -vex
WARN="-W -Wall -Wextra"
INCLUDE="-isystem /c/libs/boost-trunk"
OPT="-Ofast"
g++ -x c++ - -std=gnu++1y $INCLUDE $WARN $OPT -o a <<__EOF && ./a && echo -e "\e[1;32msucceeded\e[0m" || echo -e "\e[1;31mfailed\e[0m"
#include <boost/assert.hpp>
#include <boost/variant.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/type_traits.hpp>
#include <type_traits>
#include <cstdlib>
struct A
{
A() = default;
};
static_assert( std::is_constructible< A >::value, " A()" );
static_assert(!std::is_constructible< A, int >::value, "!A(int)" );
static_assert(!std::is_constructible< A, int, int >::value, "!A(int, int)");
struct B
{
B(int) {}
};
static_assert(!std::is_constructible< B >::value, "!B()" );
static_assert( std::is_constructible< B, int >::value, " B(int)" );
static_assert(!std::is_constructible< B, int, int >::value, "!B(int, int)");
struct C
{
C(int, int) {}
};
static_assert(!std::is_constructible< C >::value, "!C()" );
static_assert(!std::is_constructible< C, int >::value, "!C(int)" );
static_assert( std::is_constructible< C, int, int >::value, " C(int, int)");
using V = boost::variant< A, B, C >;
template< typename V,
typename ...O >
inline constexpr
V construct(O &&... _o)
{
using types = typename V::types;
using predicate = std::is_constructible< boost::mpl::_1, O... >; // I think, that the problem is exactly here.
using iter = typename boost::mpl::find_if< types, predicate >::type;
using deduced_type = typename boost::mpl::deref< iter >::type;
#if 1
return deduced_type(std::forward< O >(_o)...);
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
return deduced_type{std::forward< O >(_o)...}; // second part of the question
#pragma GCC diagnostic pop
#endif
}
int main()
{
V a = construct< V >();
BOOST_ASSERT(a.type() == typeid(A));
V b = construct< V >(0);
BOOST_ASSERT(b.type() == typeid(B));
V c = construct< V >(0, 0);
BOOST_ASSERT(c.type() == typeid(C));
return EXIT_SUCCESS;
}
__EOF
Той създава прекрасен пакет от съобщения за грешка, чието основно значение, както разбирам, е, че std::is_constructible
не е съвместим с библиотеката boost::mpl::
(или по-точно не е съвместим с контейнери от boost::mpl::
). На свой ред, самата библиотека boost::
не съдържа (уж съвместима) характеристика на типа boost::is_constructible
.
Друг свързан проблем е да се работи с класове като struct A {}; struct B {int _1;}; struct C {int _1; int _2;};
и да се конструират чрез фигурни скоби, а не скоби. Основният аспект на последния споменат проблем е липсата на черта на типа, която извежда дали даден тип може да бъде конструиран от някакъв пакет от аргументи. Решението не работи с boost::mpl::
.
boost::mpl::lambda
- person K-ballo   schedule 03.01.2014is_braces_constructible
в отговора, който сте свързали. Не разбирам защо това се компилира, а вашата версия не, така че се надявам да получите добър отговор и и двамата да научим. (Промених безвъзмездно функциятаconstruct
следвайки съвета тук, за да получите по-малко шумна грешка, когато използвате напримерV d=construct<V>(0,0,0)
, така че го променете обратно, ако искате). - person llonesmiz   schedule 03.01.2014!!predicate::apply< T >::type::value
трябва да има смисъл. - person Tomilov Anatoliy   schedule 04.01.2014