我试图使用 incomplete包装类和 std::vector作为我的间接技术来定义和访问“递归” 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.

代码:

>按预期编译和运行:

> g(测试版本:6.1和7),libstdc.
> clang(测试版本:3.8),libstdc.
>(作为奖励,它也适用于std :: variant进行适当的更改!)

>无法编译:

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

为什么代码没有用libc编译? (这可能是libc的N4510实现中需要报告的缺陷吗?)

该错误似乎表明该变体未能检测到应该初始化哪些成员,但实际上我无法理解它.我也对使用libstdc(具有相同的boost版本)按预期工作的事实感到困惑.

解决方法

我在回溯中看到了这个:

note: in instantiation of function template specialization
my_variant_wrapper::my_variant_wrapper<my_variant_wrapper &>
requested here

这清楚地表明您的构造函数模板正在劫持复制构造函数.

限制它,你的问题就消失了.

实现之间的区别是由于vector的复制构造函数复制元素的方式. libstdc将源元素视为const:

vector(const vector& __x)
  : _Base(__x.size(),_Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator()))
{
    this->_M_impl._M_finish =
    std::__uninitialized_copy_a(__x.begin(),__x.end(),this->_M_impl._M_start,_M_get_Tp_allocator());
}

因为在const vector&上调用了begin()和end(). x,它们返回常量迭代器.

libc将源元素视为非const:

template <class _Tp,class _Allocator>
vector<_Tp,_Allocator>::vector(const vector& __x)
    : __base(__alloc_traits::select_on_container_copy_construction(__x.__alloc()))
{
#if _LIBCPP_DEBUG_LEVEL >= 2
    __get_db()->__insert_c(this);
#endif
    size_type __n = __x.size();
    if (__n > 0)
    {
        allocate(__n);
        __construct_at_end(__x.__begin_,__x.__end_,__n);
    }
}

__begin_和__end_是指针,由于const很浅,__ x的常量不会使指针成为const.

两者都是一致的,因为copyInsertable需要来自const和非const源的可复制性.但是,您的模板仅劫持从非const复制(因为它失去了模板/非模板仲裁器对const case的复制),因此您只能在libc中看到问题.

使用包含不完整类型的`std :: vector`递归定义和访问`boost :: variant` – libstdc vs libc的更多相关文章

  1. ios – 嵌套递归函数

    我试图做一个嵌套递归函数,但是当我编译时,编译器崩溃.这是我的代码:编译器记录arehere解决方法有趣的…它似乎也许在尝试在定义之前捕获到内部的引用时,它是bailing?以下修复它为我们:当然没有嵌套,我们根本没有任何问题,例如以下工作完全如预期:我会说:报告!

  2. 在编译时编译Xcode中的C类错误:stl vector

    我有一个C类,用gcc和可视化工作室中的寡妇在linux上编译.boid.h:并在boid.cpp中:但是,当我在Xcode中编译此代码时,我收到以下错误:有任何想法吗?我以为你可以使用C/C++代码并在Xcode中编译没有问题?.m文件被视为具有Objective-C扩展名的.c文件..mm文件被视为具有Objective-C扩展名的.cpp文件,那么它被称为Objective-C只需将.m文件重命名为.mm,右键单击或按住Ctrl键并在Xcode中的文件中选择重命名.

  3. swift override --有一个递归问题未解决

    classca{varcount:Int{get{return1;}set{self.count=newValue;}}funcdescribe()->String{return"ca";}}classcb:ca{overridefuncdescribe()->String{return"cb";}overridevarcount:Int{get{return2;}set{//引起了递归调用,未找

  4. Swift2.0语言教程之函数嵌套调用形式

    Swift2.0语言教程之函数嵌套调用形式Swift2.0语言函数嵌套调用形式在Swift中,在函数中还可以调用函数,从而形成嵌套调用。以下将对这两种调用进行详细讲解。调用方式如图7.4所示。图7.4函数嵌套的形式以下将使用函数的嵌套调用实现对s=22!这个数值,即调用f1()函数,计算22,结果为4,然后在调用f2()函数,对4的阶乘求取,计算完成22!但是在Swift语言中递归必须要有一个满足结束的条件。

  5. swift2 运算符函数

    运算符函数前置或后置运算符函数前标注prefix或postfix组合赋值表达式比较运算符自定义运算符在自定义运算符中还可以设定自定义运算符的优先级和结合性,来处理更复杂的任务。

  6. 【Swift】学习笔记(九)——枚举

    因为类完全可以替代枚举。不过swift中也有许多类的特性被枚举支持。这样判断必须穷举所有成员,否则就需要增加default这个选项了。使用递归枚举时,编译器会插入一个中间层。

  7. Swift实现的快速排序及sorted方法的对比

    Swift语言有着优秀的函数式编程能力,面试的时候面试官都喜欢问我们快速排序,那么用Swift如何实现一个快速排序呢?然后实现快速排序的方法:可以发现使用Swift实现快速排序的代码非常的简洁。在看完这段代码后我做了如下思考:既然是排序,那么必然可以使用系统的sorted方法,效果如何呢?对于快排最头疼的顺序性数组,sorted的重复次数只有n次!说明在面对这种类型的数组的时候sorted方法进行过判断,直接输出了。

  8. Swift高级运算符(Advanced Operators)

    按位运算符~1变0,0变1。$全1得1,其他为0|有1得1,其他为0^相异为1,相同为0整体右移,左边填0。算子函数上面讲解的都是简单的运算符,下面的是为对象添加运算符,使之可计算。符号在中间前缀和后缀前缀关键字prefix后缀关键字postfix复合赋值运算符这里用+=举例。

  9. 《swift2.0 官方教程中文版》 第2章-08枚举

    importFoundation//在Swift中,枚举类型是一等公民。像Swift中其他类型一样,它们的名字必须以一个大写字母开头。给枚举类型起一个单数名字而不是复数名字,以便于读起来更加容易理解:vardirectionToHead=Compasspoint.West//directionToHead的类型可以在它被Compasspoint的一个可能值初始化时推断出来。//使用枚举成员的rawValue属性可以访问该枚举成员的原始值:letearthsOrder=Planet2.Earth.rawVa

  10. swift枚举

    Swift中的枚举更加灵活,不必给每一个枚举成员提供一个值。它是Directionoperation类型,因为swift中的枚举不会自动给成员赋值为0,1…枚举类型易扩展。原始值的隐式赋值在使用原始值为整数或者字符串类型的枚举时,不需要显式地为每一个枚举成员设置原始值,Swift将会自动为你赋值。

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部