对于不可复制的对象,boost :: optional vs std :: optional

时间:2018-01-19 11:58:59

标签: c++ boost visual-studio-2015 visual-studio-2017 language-lawyer

我尝试从VS2015更新到VS2017,以下代码在较新版本中无效。如您所见,定义了一个移动构造函数,它自动删除复制构造函数。

#include <boost/optional.hpp>
#include <vector>

struct Foo {
    Foo() {}
    Foo(Foo&& other) {}
};

int main() {
    std::vector<boost::optional<Foo>> foos;
    foos.resize(42);
    return 0;
}

编译错误是

1>...\boost\dist\include\boost-1_66\boost\optional\optional.hpp(384): error C2280: 'Foo::Foo(const Foo &)': attempting to reference a deleted function
1>...\main.cpp(7): note: compiler has generated 'Foo::Foo' here
1>...\boost\dist\include\boost-1_66\boost\optional\optional.hpp(383): note: while compiling class template member function 'void boost::optional_detail::optional_base<T>::construct(const Foo &)'
1>        with
1>        [
1>            T=Foo
1>        ]
1>...\boost\dist\include\boost-1_66\boost\optional\optional.hpp(181): note: see reference to function template instantiation 'void boost::optional_detail::optional_base<T>::construct(const Foo &)' being compiled
1>        with
1>        [
1>            T=Foo
1>        ]
1>...\boost\dist\include\boost-1_66\boost\optional\optional.hpp(831): note: see reference to class template instantiation 'boost::optional_detail::optional_base<T>' being compiled
1>        with
1>        [
1>            T=Foo
1>        ]
1>...\msvc\14.12.25827\include\vector(1902): note: see reference to class template instantiation 'boost::optional<Foo>' being compiled
1>...\msvc\14.12.25827\include\vector(1901): note: while compiling class template member function 'boost::optional<Foo> *std::vector<boost::optional<Foo>,std::allocator<_Ty>>::_Udefault(boost::optional<Foo> *,const unsigned __int64)'
1>        with
1>        [
1>            _Ty=boost::optional<Foo>
1>        ]
1>...\msvc\14.12.25827\include\vector(1528): note: see reference to function template instantiation 'boost::optional<Foo> *std::vector<boost::optional<Foo>,std::allocator<_Ty>>::_Udefault(boost::optional<Foo> *,const unsigned __int64)' being compiled
1>        with
1>        [
1>            _Ty=boost::optional<Foo>
1>        ]
1>...\main.cpp(10): note: see reference to class template instantiation 'std::vector<boost::optional<Foo>,std::allocator<_Ty>>' being compiled
1>        with
1>        [
1>            _Ty=boost::optional<Foo>
1>        ]
1>...\main.cpp(7): note: 'Foo::Foo(const Foo &)': function was implicitly deleted because 'Foo' has a user-defined move constructor

现在有趣的是,当我使用std::optional而不是boost::optional时,它会编译。我不确定问题是什么,应该责怪谁:我,boost,microsoft,c ++标准?谁知道发生了什么?

这是一个已知问题吗?它是一个提升中的错误还是正确的,它不起作用?

1 个答案:

答案 0 :(得分:1)

这似乎是STL实施的一个问题。

从最新的草案,n4700:

26.2.1一般容器要求 [container.requirements.general]定义DefaultInsertableMoveInsertable,并且还部分说明:

  

T CopyInsertable 进入X意味着除了T MoveInsertable进入X之外,以下表达式格式正确:

allocator_traits<A>::construct(m, p, v)
     

及其评估会导致以下后置条件成立:v的值保持不变,相当于*p

(在这种情况下,Tboost::optional<Foo>Xstd::vector<T>。)

显然,TDefaultInsertableMoveInsertable,而不是CopyInsertable

26.3.11.3 vector容量 [vector.capacity]部分声明:

void resize(size_type sz);
     

效果:如果sz < size(),则会删除序列中的最后size() - sz个元素。否则,将sz - size()默认插入的元素附加到序列中。

     

要求: T应为MoveInsertableDefaultInsertable*this

     

备注:如果除了非CopyInsertable T的移动构造函数之外引发异常,则不会产生任何影响。

虽然我没有C ++ 11或C ++ 14的官方副本,但基于工作副本,C ++ 11没有&#34; 备注:&#34 ;段落略有不同&#34; 要求:&#34;段:

  

要求: T CopyInsertable*this

因此,foos.resize(42)在C ++ 11中的格式不正确,但它应该在C ++ 14中很好地形成,因为TMoveInsertable的要求和{ {1}}对矢量感到满意。

我已确认@patatahooligan's commentDefaultInsertable添加到noexcept移动构造函数允许代码在Clang和g ++ 7.2.0中编译。但是,除非我误读标准,否则不要求非Foo CopyInsertable的移动构造函数为noexcept;事实上,该标准似乎允许非T CopyInsertable移动构造函数可能抛出异常,在这种情况下,它不能保证是否存在异常的效果。

更新我已提交GCC错误8398183982