I tried to update from VS2015 to VS2017 and the code below does not work in the newer version. As you can see a move constructor is defined which automatically deletes the copy constructor.
#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;
}
The compilation error is
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
Now the interesting thing is that it does compile when I use std::optional instead of boost::optional. I am not really sure what the issue is and who to blame: me, boost, microsoft, the c++ standard? Anyone knows what is going on?
Is this a known issue? Is it a bug in boost or is it correct that it does not work?
This appears to be an issue with the STL implementations.
From the latest draft, n4700:
26.2.1 General container requirements [container.requirements.general] defines DefaultInsertable and MoveInsertable, and also states in part:
TisCopyInsertableintoXmeans that, in addition toTbeingMoveInsertableintoX, the following expression is well-formed:allocator_traits<A>::construct(m, p, v)and its evaluation causes the following postcondition to hold: The value of
vis unchanged and is equivalent to*p.
(In this case, T is boost::optional<Foo>, X is std::vector<T>.)
Clearly, T is DefaultInsertable and MoveInsertable but not CopyInsertable.
26.3.11.3 vector capacity [vector.capacity] states in part:
void resize(size_type sz);Effects: If
sz < size(), erases the lastsize() - szelements from the sequence. Otherwise, appendssz - size()default-inserted elements to the sequence.Requires:
Tshall beMoveInsertableandDefaultInsertableinto*this.Remarks: If an exception is thrown other than by the move constructor of a non-
CopyInsertableTthere are no effects.
Although I do not possess official copies of C++11 or C++14, based on working copies, C++11 did not have the "Remarks:" paragraph and had a slightly different "Requires:" paragraph:
Requires:
Tshall beCopyInsertableinto*this.
Therefore, foos.resize(42) is not well-formed in C++11, but it should be well-formed in C++14 because the requirements that T be MoveInsertable and DefaultInsertable into the vector are satisfied.
I have confirmed @patatahooligan's comment that adding noexcept to the Foo move constructor allows the code to compile in Clang and g++ 7.2.0. However, unless I am misreading the standard, it is not a requirement that a non-CopyInsertable T's move constructor be noexcept; in fact, the standard seems to allow for the possibility that a non-CopyInsertable T's move constructor can throw an exception, in which case it's not guaranteed whether there were effects.
UPDATE I have filed GCC Bugs 83981 and 83982.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With