Je suis en train de définir et de visiter un « récursive » boost::variant
en utilisant une classe wrapper incomplete et std::vector
comme mes techniques d'indirection. Ma mise en œuvre fonctionne avec libstdC++, mais pas avec libC++.récursive la définition et la visite d'un `boost :: variant`` l'aide d'un std :: vECTOR` contenant un type incomplet - libstdC++ vs libC++
C'est la façon dont je suis en train de définir ma variante:
struct my_variant_wrapper;
using my_variant_array = std::vector<my_variant_wrapper>; // <- indirection here
using my_variant = boost::variant<int, my_variant_array>;
struct my_variant_wrapper
{
my_variant _v;
template <typename... Ts>
my_variant_wrapper(Ts&&... xs) : _v(std::forward<Ts>(xs)...) { }
};
J'utilise std::vector
pour introduire indirection (de sorte que l'allocation dynamique empêchera my_variant
d'avoir une taille infinie).
Je suis tout à fait confiant que je suis autorisé à utiliser std::vector<my_variant_wrapper>
, où my_variant_wrapper
est un incomplete type, en raison de paper N4510("Minimal incomplete type support for standard containers"):
Le document a été approuvé, selon WG21's 2015 page. Les caractéristiques ont toujours été supportées dans libstdC++, selon this page. Il a été implémenté dans libC++ 3.6, selon this page.
Je visitais alors la variante comme suit:
struct my_visitor
{
void operator()(int x) const { }
void operator()(const my_variant_array& arr) const
{
for(const auto& x : arr)
boost::apply_visitor(*this, x._v);
}
};
int main()
{
my_variant v0 = my_variant_array{
my_variant{1}, my_variant{2}, my_variant_array{
my_variant{3}, my_variant{4}
}
};
boost::apply_visitor(my_visitor{}, v0);
}
A minimal complete example is available on coliru.
J'utilise les drapeaux suivants:
std = C++ 1z -Wall -Wextra -Wpedantic
BOOST_VERSION
évalue à106100
.
Le code:
Compile et exécute comme prévu sur:
g ++ (versions testées: 6.1 et 7), avec libstdC++.
clang ++ (versions testées: 3.8), avec libstdC++.
(comme un bonus, cela fonctionne aussi avec
std::variant
en apportant les modifications appropriées!)
ne réussit pas à compiler sur:
- clang ++ (versions testées : 3.8, 4), avec libC++.
Ceci est l'erreur que je reçois lors de la compilation sur clang ++ avec libC++:
In file included from prog.cc:2:
In file included from /usr/local/boost-1.61.0/include/boost/variant.hpp:17:
/usr/local/boost-1.61.0/include/boost/variant/variant.hpp:1537:28: error: no matching member function for call to 'initialize'
initializer::initialize(
~~~~~~~~~~~~~^~~~~~~~~~
/usr/local/boost-1.61.0/include/boost/variant/variant.hpp:1692:9: note: in instantiation of function template specialization 'boost::variant<int, std::__1::vector<my_variant_wrapper, std::__1::allocator<my_variant_wrapper> > >::convert_construct<my_variant_wrapper>' requested here
convert_construct(operand, 1L);
^
prog.cc:15:38: note: in instantiation of function template specialization 'boost::variant<int, std::__1::vector<my_variant_wrapper, std::__1::allocator<my_variant_wrapper> > >::variant<my_variant_wrapper>' requested here
my_variant_wrapper(Ts&&... xs) : _v(std::forward<Ts>(xs)...) { }
^
/usr/local/libcxx-head/include/c++/v1/memory:1783:31: note: in instantiation of function template specialization 'my_variant_wrapper::my_variant_wrapper<my_variant_wrapper &>' requested here
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
^
/usr/local/libcxx-head/include/c++/v1/memory:1694:18: note: in instantiation of function template specialization 'std::__1::allocator<my_variant_wrapper>::construct<my_variant_wrapper, my_variant_wrapper &>' requested here
{__a.construct(__p, _VSTD::forward<_Args>(__args)...);}
^
...
The full error is available on wandbox.
Pourquoi le code ne compilent avec libC++?(Serait-ce un défaut dans la mise en œuvre libc de ++ 's N4510 qui doit être rapporté?)
L'erreur semble indiquer que la variante ne parvient pas à détecter ce que les membres doivent être initialisées, mais honnêtement, je ne pouvais pas faire beaucoup de sens de cela. Je suis également confus par le fait que l'utilisation libstdC++(avec la même version de boost) fonctionne comme prévu.
Génial, merci! [Il compile avec ** libC++ **] (http://melpon.org/wandbox/permlink/TCBfoFPrEZHFE8G0) lorsqu'il est contraint. Je suis toujours perplexe sur la raison pour laquelle cette erreur ne se produit qu'avec libC++. Pourriez-vous élaborer sur ce point? –
@VittorioRomeo Juste passé un peu plus de temps à creuser - voir modifier. –
Le vecteur de libC++ tente de copier-construire les éléments vectoriels à l'aide d'une référence de lvalue non-const, alors que libstdC++ passe une référence const lvalue. Parce que libC++ utilise une référence non-const, il choisit le constructeur de modèle au lieu du constructeur de copie. – EricWF