我正在尝试使用incomplete包装类和std::vector作为我的间接技术来定义和访问"recursive" boost::variant . 我的实现适用于 libstdc++ ,但不适用于 libc++ .
这是我定义我的变体的方式:
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)...) { }
};
我使用 std::vector
来引入间接(因此动态分配将阻止 my_variant
具有无限大小) .
我很有信心我被允许使用 std::vector<my_variant_wrapper>
,其中 my_variant_wrapper
是incomplete type,因为paper N4510 ("Minimal incomplete type support for standard containers"):
-
根据WG21's 2015 page,该文件获得批准 .
-
根据this page, libstdc++ 始终支持这些功能 .
根据this page,
- 在 libc++ 3.6 实施 .
我随后访问变体如下:
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.
- 我正在使用以下标志:
-std = c 1z -Wall -Wextra -Wpedantic
BOOST_VERSION
评估为106100
.
代码:
意图
-
Compiles and runs
-
g(测试版本:6.1和7), libstdc++ .
-
clang(测试版本:3.8), libstdc++ .
-
(作为奖励,通过进行适当的更改,它也适用于
std::variant
!) -
Fails to compile 上:
-
clang(测试版本:3.8,4), libc++ .
这是我在使用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.
Why is the code not compiling with libc++? (这可能是libc的N4510实现中需要报告的缺陷吗?)
该错误似乎表明该变体未能检测到应该初始化哪些成员,但我真的无法理解它 . 我也对使用 libstdc++ (具有相同的boost版本)按预期工作的事实感到困惑 .
1 回答
我在回溯中看到了这个:
这清楚地表明您的构造函数模板正在劫持复制构造函数 .
限制它,你的问题就消失了 .
实现之间的区别是由于
vector
的复制构造函数复制元素的方式 . libstdc将源元素视为const
:因为
begin()
和end()
在const vector& x
上被调用,所以它们返回常量迭代器 .libc将源元素视为非
const
:__begin_
和__end_
是pointer
s,并且由于const
浅,__x
的const
-ness不会成为指针const
.两者都符合要求,因为
CopyInsertable
要求来自const
和非const
来源的可复制性 . 但是,您的模板仅劫持从非const
复制(因为它失去了模板/非模板仲裁器从const
案例中复制),因此您只能在libc中看到问题 .