does vs2017 need explicit move constructor declaration

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
11
down vote

favorite
4












The below code can be compiled successfully using vs2015, but failed using vs2017. vs2017 report "error C2280: “std::pair<const _Kty,_Ty>::pair(const std::pair<const _Kty,_Ty> &)”: attempting to reference a deleted function".



#include <unordered_map>
#include <memory>

struct Node

std::unordered_map<int, std::unique_ptr<int>> map_;
//uncomment the following two lines will pass vs2017 compile
//Node(Node&& o) = default;
//Node() = default;
;

int main()

std::vector<Node> vec;
Node node;
vec.push_back(std::move(node));
return 0;



It looks like vs2017 need explicit move constructor declaration. could anybody explain the reason? thanks.










share|improve this question









New contributor




finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



















  • You're missing #include <vector> but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?
    – rubenvb
    5 hours ago











  • I can confirm this code fails with error code under vs2017 15.4.2.
    – marcinj
    5 hours ago










  • Confirm also in the VS2017 15.9.0 Preview 3.
    – Evg
    5 hours ago














up vote
11
down vote

favorite
4












The below code can be compiled successfully using vs2015, but failed using vs2017. vs2017 report "error C2280: “std::pair<const _Kty,_Ty>::pair(const std::pair<const _Kty,_Ty> &)”: attempting to reference a deleted function".



#include <unordered_map>
#include <memory>

struct Node

std::unordered_map<int, std::unique_ptr<int>> map_;
//uncomment the following two lines will pass vs2017 compile
//Node(Node&& o) = default;
//Node() = default;
;

int main()

std::vector<Node> vec;
Node node;
vec.push_back(std::move(node));
return 0;



It looks like vs2017 need explicit move constructor declaration. could anybody explain the reason? thanks.










share|improve this question









New contributor




finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



















  • You're missing #include <vector> but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?
    – rubenvb
    5 hours ago











  • I can confirm this code fails with error code under vs2017 15.4.2.
    – marcinj
    5 hours ago










  • Confirm also in the VS2017 15.9.0 Preview 3.
    – Evg
    5 hours ago












up vote
11
down vote

favorite
4









up vote
11
down vote

favorite
4






4





The below code can be compiled successfully using vs2015, but failed using vs2017. vs2017 report "error C2280: “std::pair<const _Kty,_Ty>::pair(const std::pair<const _Kty,_Ty> &)”: attempting to reference a deleted function".



#include <unordered_map>
#include <memory>

struct Node

std::unordered_map<int, std::unique_ptr<int>> map_;
//uncomment the following two lines will pass vs2017 compile
//Node(Node&& o) = default;
//Node() = default;
;

int main()

std::vector<Node> vec;
Node node;
vec.push_back(std::move(node));
return 0;



It looks like vs2017 need explicit move constructor declaration. could anybody explain the reason? thanks.










share|improve this question









New contributor




finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











The below code can be compiled successfully using vs2015, but failed using vs2017. vs2017 report "error C2280: “std::pair<const _Kty,_Ty>::pair(const std::pair<const _Kty,_Ty> &)”: attempting to reference a deleted function".



#include <unordered_map>
#include <memory>

struct Node

std::unordered_map<int, std::unique_ptr<int>> map_;
//uncomment the following two lines will pass vs2017 compile
//Node(Node&& o) = default;
//Node() = default;
;

int main()

std::vector<Node> vec;
Node node;
vec.push_back(std::move(node));
return 0;



It looks like vs2017 need explicit move constructor declaration. could anybody explain the reason? thanks.







c++ visual-studio-2017 move-constructor






share|improve this question









New contributor




finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 12 mins ago









Mike Kinghan

28.7k762106




28.7k762106






New contributor




finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 5 hours ago









finn

592




592




New contributor




finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











  • You're missing #include <vector> but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?
    – rubenvb
    5 hours ago











  • I can confirm this code fails with error code under vs2017 15.4.2.
    – marcinj
    5 hours ago










  • Confirm also in the VS2017 15.9.0 Preview 3.
    – Evg
    5 hours ago
















  • You're missing #include <vector> but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?
    – rubenvb
    5 hours ago











  • I can confirm this code fails with error code under vs2017 15.4.2.
    – marcinj
    5 hours ago










  • Confirm also in the VS2017 15.9.0 Preview 3.
    – Evg
    5 hours ago















You're missing #include <vector> but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?
– rubenvb
5 hours ago





You're missing #include <vector> but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?
– rubenvb
5 hours ago













I can confirm this code fails with error code under vs2017 15.4.2.
– marcinj
5 hours ago




I can confirm this code fails with error code under vs2017 15.4.2.
– marcinj
5 hours ago












Confirm also in the VS2017 15.9.0 Preview 3.
– Evg
5 hours ago




Confirm also in the VS2017 15.9.0 Preview 3.
– Evg
5 hours ago












3 Answers
3






active

oldest

votes

















up vote
6
down vote













Minimal example:



#include <memory>
#include <unordered_map>
#include <vector>

int main()
std::vector<std::unordered_map<int, std::unique_ptr<int>>> vec;
vec.reserve(1);



Live demo on GodBolt: https://godbolt.org/z/VApPkH.




Another example:



std::unordered_map<int, std::unique_ptr<int>> m;
auto m2 = std::move(m); // ok
auto m3 = std::move_if_noexcept(m); // error C2280



UPDATE



I believe the compilation error is legal. Vector's reallocation function can transfer (contents of) elements by using std::move_if_noexcept, therefore preferring copy constructors to throwing move constructors.



In libstdc++ (GCC) / libc++ (clang), move constructor of std::unordered_map is (seemingly) noexcept. Consequently, copy constructor is not at all involved.



On the other hand, implemnetation from MSVC 2017 seemingly does not specify move constructor of std::unordered_map as noexcept. Therefore, vector's reallocation function via std::move_if_noexcept tries to invoke copy constructor. This violates the requirements for containers in general, since value type (std::pair<const int, std::unique_ptr<int>> in this case) is not copy-insertable (see, e.g., here http://eel.is/c++draft/container.requirements.general#tab:containers.container.requirements).



Finally, if you user-define move constructor, the implicitly declared copy constructor is defined as deleted. And, deleted implicitly declared copy constructor does not participate in overload resolution.






share|improve this answer






















  • Is this realy a bug? std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>> is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
    – Oliv
    41 mins ago










  • @Oliv That's a good question. It seems that the problem is that the move constructor of std::unordered_map is not noexcept in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it is noexcept.
    – Daniel Langr
    24 mins ago











  • @Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
    – Daniel Langr
    15 mins ago


















up vote
4
down vote













When you declare a move constructor, the implicitly declared copy constructor is defined as deleted. On the other hand, when you don't declare a move constructor, the compiler implicitly defines the copy constructor when it need it. And this implicit definition is ill-formed.



unique_ptr is not CopyInsertable in a container that uses a standard allocator because it is not copy constructible so the copy constructor of map_ is ill-formed (it could have been declared as deleted, but this is not required by the standard).



As your example code show us, with newer version of MSVC, this ill-formed definition is generated with this example code. I do not think there is something in the standard that forbids it (even if this is realy surprising).



So you should indeed ensure that the copy constructor of Node is declared or implicitly defined as deleted.






share|improve this answer


















  • 1




    Im wondering as to why the issue is not seen with clang or gcc ?
    – darune
    2 hours ago






  • 1




    @darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
    – Oliv
    2 hours ago






  • 1




    I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor of std::unordered_map (and therefore of Node) is not noexcept? Then, push_back, i.e., emplace_back, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
    – Daniel Langr
    1 hour ago







  • 3




    The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible with unordered_map, and ended up having to use private inheritance from std::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type where AllowCopy is empty and DisallowCopy has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
    – Arne Vogel
    1 hour ago






  • 2




    is_nothrow_move_constructible_v<Node> is false in MSVC, so it tries to copy and fails; it is true in gcc, so it moves. If is_nothrow_move_constructible_v<Node> is forced to become false in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree on is_nothrow_move_constructible_v<Node> value?
    – Evg
    33 mins ago

















up vote
2
down vote













Let's look at the std::vector source code (I replaced pointer and _Ty with actual types):



void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
// move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());


void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
// copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());


void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
// move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>);



If Node is no-throw move-constructible or is not copy-constructible, _Uninitialized_move is called, otherwise, _Uninitialized_copy is called.



The problem is that the type trait std::is_copy_constructible_v is true for Node if you do not declare a move constructor explicitly. This declaration makes copy-constructor deleted.



libstdc++ implements std::vector in a similar way, but there std::is_nothrow_move_constructible_v<Node> is true in contrast to MSVC, where it is false. So, move semantics is used and the compiler does not try to generate the copy-constructor.



But if we force is_nothrow_move_constructible_v to become false



struct Base 
Base() = default;
Base(const S&) = default;
Base(Base&&) noexcept(false)
;

struct Node : Base
std::unordered_map<int, std::unique_ptr<int>> map;
;

int main()
std::vector<Node> vec;
vec.reserve(1);



the same error occurs:



/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~





share|improve this answer


















  • 1




    Im wondering as to why the issue is not seen with clang or gcc ?
    – darune
    2 hours ago






  • 1




    @darune, the dumb answer is because gcc's and clang's implementations do not rely on std::is_copy_constructible in this particular piece of code. I don't have a better answer now.
    – Evg
    2 hours ago










  • If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
    – darune
    2 hours ago











  • @darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
    – Evg
    1 hour ago










  • @darune, added some info about in libstdc++.
    – Evg
    51 mins ago










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);






finn is a new contributor. Be nice, and check out our Code of Conduct.









 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53168836%2fdoes-vs2017-need-explicit-move-constructor-declaration%23new-answer', 'question_page');

);

Post as a guest






























3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
6
down vote













Minimal example:



#include <memory>
#include <unordered_map>
#include <vector>

int main()
std::vector<std::unordered_map<int, std::unique_ptr<int>>> vec;
vec.reserve(1);



Live demo on GodBolt: https://godbolt.org/z/VApPkH.




Another example:



std::unordered_map<int, std::unique_ptr<int>> m;
auto m2 = std::move(m); // ok
auto m3 = std::move_if_noexcept(m); // error C2280



UPDATE



I believe the compilation error is legal. Vector's reallocation function can transfer (contents of) elements by using std::move_if_noexcept, therefore preferring copy constructors to throwing move constructors.



In libstdc++ (GCC) / libc++ (clang), move constructor of std::unordered_map is (seemingly) noexcept. Consequently, copy constructor is not at all involved.



On the other hand, implemnetation from MSVC 2017 seemingly does not specify move constructor of std::unordered_map as noexcept. Therefore, vector's reallocation function via std::move_if_noexcept tries to invoke copy constructor. This violates the requirements for containers in general, since value type (std::pair<const int, std::unique_ptr<int>> in this case) is not copy-insertable (see, e.g., here http://eel.is/c++draft/container.requirements.general#tab:containers.container.requirements).



Finally, if you user-define move constructor, the implicitly declared copy constructor is defined as deleted. And, deleted implicitly declared copy constructor does not participate in overload resolution.






share|improve this answer






















  • Is this realy a bug? std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>> is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
    – Oliv
    41 mins ago










  • @Oliv That's a good question. It seems that the problem is that the move constructor of std::unordered_map is not noexcept in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it is noexcept.
    – Daniel Langr
    24 mins ago











  • @Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
    – Daniel Langr
    15 mins ago















up vote
6
down vote













Minimal example:



#include <memory>
#include <unordered_map>
#include <vector>

int main()
std::vector<std::unordered_map<int, std::unique_ptr<int>>> vec;
vec.reserve(1);



Live demo on GodBolt: https://godbolt.org/z/VApPkH.




Another example:



std::unordered_map<int, std::unique_ptr<int>> m;
auto m2 = std::move(m); // ok
auto m3 = std::move_if_noexcept(m); // error C2280



UPDATE



I believe the compilation error is legal. Vector's reallocation function can transfer (contents of) elements by using std::move_if_noexcept, therefore preferring copy constructors to throwing move constructors.



In libstdc++ (GCC) / libc++ (clang), move constructor of std::unordered_map is (seemingly) noexcept. Consequently, copy constructor is not at all involved.



On the other hand, implemnetation from MSVC 2017 seemingly does not specify move constructor of std::unordered_map as noexcept. Therefore, vector's reallocation function via std::move_if_noexcept tries to invoke copy constructor. This violates the requirements for containers in general, since value type (std::pair<const int, std::unique_ptr<int>> in this case) is not copy-insertable (see, e.g., here http://eel.is/c++draft/container.requirements.general#tab:containers.container.requirements).



Finally, if you user-define move constructor, the implicitly declared copy constructor is defined as deleted. And, deleted implicitly declared copy constructor does not participate in overload resolution.






share|improve this answer






















  • Is this realy a bug? std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>> is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
    – Oliv
    41 mins ago










  • @Oliv That's a good question. It seems that the problem is that the move constructor of std::unordered_map is not noexcept in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it is noexcept.
    – Daniel Langr
    24 mins ago











  • @Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
    – Daniel Langr
    15 mins ago













up vote
6
down vote










up vote
6
down vote









Minimal example:



#include <memory>
#include <unordered_map>
#include <vector>

int main()
std::vector<std::unordered_map<int, std::unique_ptr<int>>> vec;
vec.reserve(1);



Live demo on GodBolt: https://godbolt.org/z/VApPkH.




Another example:



std::unordered_map<int, std::unique_ptr<int>> m;
auto m2 = std::move(m); // ok
auto m3 = std::move_if_noexcept(m); // error C2280



UPDATE



I believe the compilation error is legal. Vector's reallocation function can transfer (contents of) elements by using std::move_if_noexcept, therefore preferring copy constructors to throwing move constructors.



In libstdc++ (GCC) / libc++ (clang), move constructor of std::unordered_map is (seemingly) noexcept. Consequently, copy constructor is not at all involved.



On the other hand, implemnetation from MSVC 2017 seemingly does not specify move constructor of std::unordered_map as noexcept. Therefore, vector's reallocation function via std::move_if_noexcept tries to invoke copy constructor. This violates the requirements for containers in general, since value type (std::pair<const int, std::unique_ptr<int>> in this case) is not copy-insertable (see, e.g., here http://eel.is/c++draft/container.requirements.general#tab:containers.container.requirements).



Finally, if you user-define move constructor, the implicitly declared copy constructor is defined as deleted. And, deleted implicitly declared copy constructor does not participate in overload resolution.






share|improve this answer














Minimal example:



#include <memory>
#include <unordered_map>
#include <vector>

int main()
std::vector<std::unordered_map<int, std::unique_ptr<int>>> vec;
vec.reserve(1);



Live demo on GodBolt: https://godbolt.org/z/VApPkH.




Another example:



std::unordered_map<int, std::unique_ptr<int>> m;
auto m2 = std::move(m); // ok
auto m3 = std::move_if_noexcept(m); // error C2280



UPDATE



I believe the compilation error is legal. Vector's reallocation function can transfer (contents of) elements by using std::move_if_noexcept, therefore preferring copy constructors to throwing move constructors.



In libstdc++ (GCC) / libc++ (clang), move constructor of std::unordered_map is (seemingly) noexcept. Consequently, copy constructor is not at all involved.



On the other hand, implemnetation from MSVC 2017 seemingly does not specify move constructor of std::unordered_map as noexcept. Therefore, vector's reallocation function via std::move_if_noexcept tries to invoke copy constructor. This violates the requirements for containers in general, since value type (std::pair<const int, std::unique_ptr<int>> in this case) is not copy-insertable (see, e.g., here http://eel.is/c++draft/container.requirements.general#tab:containers.container.requirements).



Finally, if you user-define move constructor, the implicitly declared copy constructor is defined as deleted. And, deleted implicitly declared copy constructor does not participate in overload resolution.







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 mins ago

























answered 1 hour ago









Daniel Langr

6,0042243




6,0042243











  • Is this realy a bug? std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>> is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
    – Oliv
    41 mins ago










  • @Oliv That's a good question. It seems that the problem is that the move constructor of std::unordered_map is not noexcept in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it is noexcept.
    – Daniel Langr
    24 mins ago











  • @Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
    – Daniel Langr
    15 mins ago

















  • Is this realy a bug? std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>> is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
    – Oliv
    41 mins ago










  • @Oliv That's a good question. It seems that the problem is that the move constructor of std::unordered_map is not noexcept in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it is noexcept.
    – Daniel Langr
    24 mins ago











  • @Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
    – Daniel Langr
    15 mins ago
















Is this realy a bug? std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>> is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
– Oliv
41 mins ago




Is this realy a bug? std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>> is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
– Oliv
41 mins ago












@Oliv That's a good question. It seems that the problem is that the move constructor of std::unordered_map is not noexcept in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it is noexcept.
– Daniel Langr
24 mins ago





@Oliv That's a good question. It seems that the problem is that the move constructor of std::unordered_map is not noexcept in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it is noexcept.
– Daniel Langr
24 mins ago













@Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
– Daniel Langr
15 mins ago





@Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
– Daniel Langr
15 mins ago













up vote
4
down vote













When you declare a move constructor, the implicitly declared copy constructor is defined as deleted. On the other hand, when you don't declare a move constructor, the compiler implicitly defines the copy constructor when it need it. And this implicit definition is ill-formed.



unique_ptr is not CopyInsertable in a container that uses a standard allocator because it is not copy constructible so the copy constructor of map_ is ill-formed (it could have been declared as deleted, but this is not required by the standard).



As your example code show us, with newer version of MSVC, this ill-formed definition is generated with this example code. I do not think there is something in the standard that forbids it (even if this is realy surprising).



So you should indeed ensure that the copy constructor of Node is declared or implicitly defined as deleted.






share|improve this answer


















  • 1




    Im wondering as to why the issue is not seen with clang or gcc ?
    – darune
    2 hours ago






  • 1




    @darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
    – Oliv
    2 hours ago






  • 1




    I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor of std::unordered_map (and therefore of Node) is not noexcept? Then, push_back, i.e., emplace_back, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
    – Daniel Langr
    1 hour ago







  • 3




    The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible with unordered_map, and ended up having to use private inheritance from std::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type where AllowCopy is empty and DisallowCopy has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
    – Arne Vogel
    1 hour ago






  • 2




    is_nothrow_move_constructible_v<Node> is false in MSVC, so it tries to copy and fails; it is true in gcc, so it moves. If is_nothrow_move_constructible_v<Node> is forced to become false in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree on is_nothrow_move_constructible_v<Node> value?
    – Evg
    33 mins ago














up vote
4
down vote













When you declare a move constructor, the implicitly declared copy constructor is defined as deleted. On the other hand, when you don't declare a move constructor, the compiler implicitly defines the copy constructor when it need it. And this implicit definition is ill-formed.



unique_ptr is not CopyInsertable in a container that uses a standard allocator because it is not copy constructible so the copy constructor of map_ is ill-formed (it could have been declared as deleted, but this is not required by the standard).



As your example code show us, with newer version of MSVC, this ill-formed definition is generated with this example code. I do not think there is something in the standard that forbids it (even if this is realy surprising).



So you should indeed ensure that the copy constructor of Node is declared or implicitly defined as deleted.






share|improve this answer


















  • 1




    Im wondering as to why the issue is not seen with clang or gcc ?
    – darune
    2 hours ago






  • 1




    @darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
    – Oliv
    2 hours ago






  • 1




    I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor of std::unordered_map (and therefore of Node) is not noexcept? Then, push_back, i.e., emplace_back, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
    – Daniel Langr
    1 hour ago







  • 3




    The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible with unordered_map, and ended up having to use private inheritance from std::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type where AllowCopy is empty and DisallowCopy has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
    – Arne Vogel
    1 hour ago






  • 2




    is_nothrow_move_constructible_v<Node> is false in MSVC, so it tries to copy and fails; it is true in gcc, so it moves. If is_nothrow_move_constructible_v<Node> is forced to become false in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree on is_nothrow_move_constructible_v<Node> value?
    – Evg
    33 mins ago












up vote
4
down vote










up vote
4
down vote









When you declare a move constructor, the implicitly declared copy constructor is defined as deleted. On the other hand, when you don't declare a move constructor, the compiler implicitly defines the copy constructor when it need it. And this implicit definition is ill-formed.



unique_ptr is not CopyInsertable in a container that uses a standard allocator because it is not copy constructible so the copy constructor of map_ is ill-formed (it could have been declared as deleted, but this is not required by the standard).



As your example code show us, with newer version of MSVC, this ill-formed definition is generated with this example code. I do not think there is something in the standard that forbids it (even if this is realy surprising).



So you should indeed ensure that the copy constructor of Node is declared or implicitly defined as deleted.






share|improve this answer














When you declare a move constructor, the implicitly declared copy constructor is defined as deleted. On the other hand, when you don't declare a move constructor, the compiler implicitly defines the copy constructor when it need it. And this implicit definition is ill-formed.



unique_ptr is not CopyInsertable in a container that uses a standard allocator because it is not copy constructible so the copy constructor of map_ is ill-formed (it could have been declared as deleted, but this is not required by the standard).



As your example code show us, with newer version of MSVC, this ill-formed definition is generated with this example code. I do not think there is something in the standard that forbids it (even if this is realy surprising).



So you should indeed ensure that the copy constructor of Node is declared or implicitly defined as deleted.







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 hours ago

























answered 2 hours ago









Oliv

7,1281750




7,1281750







  • 1




    Im wondering as to why the issue is not seen with clang or gcc ?
    – darune
    2 hours ago






  • 1




    @darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
    – Oliv
    2 hours ago






  • 1




    I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor of std::unordered_map (and therefore of Node) is not noexcept? Then, push_back, i.e., emplace_back, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
    – Daniel Langr
    1 hour ago







  • 3




    The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible with unordered_map, and ended up having to use private inheritance from std::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type where AllowCopy is empty and DisallowCopy has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
    – Arne Vogel
    1 hour ago






  • 2




    is_nothrow_move_constructible_v<Node> is false in MSVC, so it tries to copy and fails; it is true in gcc, so it moves. If is_nothrow_move_constructible_v<Node> is forced to become false in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree on is_nothrow_move_constructible_v<Node> value?
    – Evg
    33 mins ago












  • 1




    Im wondering as to why the issue is not seen with clang or gcc ?
    – darune
    2 hours ago






  • 1




    @darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
    – Oliv
    2 hours ago






  • 1




    I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor of std::unordered_map (and therefore of Node) is not noexcept? Then, push_back, i.e., emplace_back, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
    – Daniel Langr
    1 hour ago







  • 3




    The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible with unordered_map, and ended up having to use private inheritance from std::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type where AllowCopy is empty and DisallowCopy has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
    – Arne Vogel
    1 hour ago






  • 2




    is_nothrow_move_constructible_v<Node> is false in MSVC, so it tries to copy and fails; it is true in gcc, so it moves. If is_nothrow_move_constructible_v<Node> is forced to become false in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree on is_nothrow_move_constructible_v<Node> value?
    – Evg
    33 mins ago







1




1




Im wondering as to why the issue is not seen with clang or gcc ?
– darune
2 hours ago




Im wondering as to why the issue is not seen with clang or gcc ?
– darune
2 hours ago




1




1




@darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
– Oliv
2 hours ago




@darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
– Oliv
2 hours ago




1




1




I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor of std::unordered_map (and therefore of Node) is not noexcept? Then, push_back, i.e., emplace_back, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
– Daniel Langr
1 hour ago





I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor of std::unordered_map (and therefore of Node) is not noexcept? Then, push_back, i.e., emplace_back, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
– Daniel Langr
1 hour ago





3




3




The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible with unordered_map, and ended up having to use private inheritance from std::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type where AllowCopy is empty and DisallowCopy has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
– Arne Vogel
1 hour ago




The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible with unordered_map, and ended up having to use private inheritance from std::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type where AllowCopy is empty and DisallowCopy has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
– Arne Vogel
1 hour ago




2




2




is_nothrow_move_constructible_v<Node> is false in MSVC, so it tries to copy and fails; it is true in gcc, so it moves. If is_nothrow_move_constructible_v<Node> is forced to become false in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree on is_nothrow_move_constructible_v<Node> value?
– Evg
33 mins ago




is_nothrow_move_constructible_v<Node> is false in MSVC, so it tries to copy and fails; it is true in gcc, so it moves. If is_nothrow_move_constructible_v<Node> is forced to become false in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree on is_nothrow_move_constructible_v<Node> value?
– Evg
33 mins ago










up vote
2
down vote













Let's look at the std::vector source code (I replaced pointer and _Ty with actual types):



void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
// move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());


void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
// copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());


void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
// move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>);



If Node is no-throw move-constructible or is not copy-constructible, _Uninitialized_move is called, otherwise, _Uninitialized_copy is called.



The problem is that the type trait std::is_copy_constructible_v is true for Node if you do not declare a move constructor explicitly. This declaration makes copy-constructor deleted.



libstdc++ implements std::vector in a similar way, but there std::is_nothrow_move_constructible_v<Node> is true in contrast to MSVC, where it is false. So, move semantics is used and the compiler does not try to generate the copy-constructor.



But if we force is_nothrow_move_constructible_v to become false



struct Base 
Base() = default;
Base(const S&) = default;
Base(Base&&) noexcept(false)
;

struct Node : Base
std::unordered_map<int, std::unique_ptr<int>> map;
;

int main()
std::vector<Node> vec;
vec.reserve(1);



the same error occurs:



/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~





share|improve this answer


















  • 1




    Im wondering as to why the issue is not seen with clang or gcc ?
    – darune
    2 hours ago






  • 1




    @darune, the dumb answer is because gcc's and clang's implementations do not rely on std::is_copy_constructible in this particular piece of code. I don't have a better answer now.
    – Evg
    2 hours ago










  • If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
    – darune
    2 hours ago











  • @darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
    – Evg
    1 hour ago










  • @darune, added some info about in libstdc++.
    – Evg
    51 mins ago














up vote
2
down vote













Let's look at the std::vector source code (I replaced pointer and _Ty with actual types):



void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
// move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());


void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
// copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());


void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
// move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>);



If Node is no-throw move-constructible or is not copy-constructible, _Uninitialized_move is called, otherwise, _Uninitialized_copy is called.



The problem is that the type trait std::is_copy_constructible_v is true for Node if you do not declare a move constructor explicitly. This declaration makes copy-constructor deleted.



libstdc++ implements std::vector in a similar way, but there std::is_nothrow_move_constructible_v<Node> is true in contrast to MSVC, where it is false. So, move semantics is used and the compiler does not try to generate the copy-constructor.



But if we force is_nothrow_move_constructible_v to become false



struct Base 
Base() = default;
Base(const S&) = default;
Base(Base&&) noexcept(false)
;

struct Node : Base
std::unordered_map<int, std::unique_ptr<int>> map;
;

int main()
std::vector<Node> vec;
vec.reserve(1);



the same error occurs:



/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~





share|improve this answer


















  • 1




    Im wondering as to why the issue is not seen with clang or gcc ?
    – darune
    2 hours ago






  • 1




    @darune, the dumb answer is because gcc's and clang's implementations do not rely on std::is_copy_constructible in this particular piece of code. I don't have a better answer now.
    – Evg
    2 hours ago










  • If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
    – darune
    2 hours ago











  • @darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
    – Evg
    1 hour ago










  • @darune, added some info about in libstdc++.
    – Evg
    51 mins ago












up vote
2
down vote










up vote
2
down vote









Let's look at the std::vector source code (I replaced pointer and _Ty with actual types):



void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
// move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());


void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
// copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());


void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
// move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>);



If Node is no-throw move-constructible or is not copy-constructible, _Uninitialized_move is called, otherwise, _Uninitialized_copy is called.



The problem is that the type trait std::is_copy_constructible_v is true for Node if you do not declare a move constructor explicitly. This declaration makes copy-constructor deleted.



libstdc++ implements std::vector in a similar way, but there std::is_nothrow_move_constructible_v<Node> is true in contrast to MSVC, where it is false. So, move semantics is used and the compiler does not try to generate the copy-constructor.



But if we force is_nothrow_move_constructible_v to become false



struct Base 
Base() = default;
Base(const S&) = default;
Base(Base&&) noexcept(false)
;

struct Node : Base
std::unordered_map<int, std::unique_ptr<int>> map;
;

int main()
std::vector<Node> vec;
vec.reserve(1);



the same error occurs:



/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~





share|improve this answer














Let's look at the std::vector source code (I replaced pointer and _Ty with actual types):



void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
// move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());


void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
// copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());


void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
// move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>);



If Node is no-throw move-constructible or is not copy-constructible, _Uninitialized_move is called, otherwise, _Uninitialized_copy is called.



The problem is that the type trait std::is_copy_constructible_v is true for Node if you do not declare a move constructor explicitly. This declaration makes copy-constructor deleted.



libstdc++ implements std::vector in a similar way, but there std::is_nothrow_move_constructible_v<Node> is true in contrast to MSVC, where it is false. So, move semantics is used and the compiler does not try to generate the copy-constructor.



But if we force is_nothrow_move_constructible_v to become false



struct Base 
Base() = default;
Base(const S&) = default;
Base(Base&&) noexcept(false)
;

struct Node : Base
std::unordered_map<int, std::unique_ptr<int>> map;
;

int main()
std::vector<Node> vec;
vec.reserve(1);



the same error occurs:



/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~






share|improve this answer














share|improve this answer



share|improve this answer








edited 42 mins ago

























answered 2 hours ago









Evg

3,41811334




3,41811334







  • 1




    Im wondering as to why the issue is not seen with clang or gcc ?
    – darune
    2 hours ago






  • 1




    @darune, the dumb answer is because gcc's and clang's implementations do not rely on std::is_copy_constructible in this particular piece of code. I don't have a better answer now.
    – Evg
    2 hours ago










  • If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
    – darune
    2 hours ago











  • @darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
    – Evg
    1 hour ago










  • @darune, added some info about in libstdc++.
    – Evg
    51 mins ago












  • 1




    Im wondering as to why the issue is not seen with clang or gcc ?
    – darune
    2 hours ago






  • 1




    @darune, the dumb answer is because gcc's and clang's implementations do not rely on std::is_copy_constructible in this particular piece of code. I don't have a better answer now.
    – Evg
    2 hours ago










  • If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
    – darune
    2 hours ago











  • @darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
    – Evg
    1 hour ago










  • @darune, added some info about in libstdc++.
    – Evg
    51 mins ago







1




1




Im wondering as to why the issue is not seen with clang or gcc ?
– darune
2 hours ago




Im wondering as to why the issue is not seen with clang or gcc ?
– darune
2 hours ago




1




1




@darune, the dumb answer is because gcc's and clang's implementations do not rely on std::is_copy_constructible in this particular piece of code. I don't have a better answer now.
– Evg
2 hours ago




@darune, the dumb answer is because gcc's and clang's implementations do not rely on std::is_copy_constructible in this particular piece of code. I don't have a better answer now.
– Evg
2 hours ago












If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
– darune
2 hours ago





If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
– darune
2 hours ago













@darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
– Evg
1 hour ago




@darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
– Evg
1 hour ago












@darune, added some info about in libstdc++.
– Evg
51 mins ago




@darune, added some info about in libstdc++.
– Evg
51 mins ago










finn is a new contributor. Be nice, and check out our Code of Conduct.









 

draft saved


draft discarded


















finn is a new contributor. Be nice, and check out our Code of Conduct.












finn is a new contributor. Be nice, and check out our Code of Conduct.











finn is a new contributor. Be nice, and check out our Code of Conduct.













 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53168836%2fdoes-vs2017-need-explicit-move-constructor-declaration%23new-answer', 'question_page');

);

Post as a guest













































































Comments

Popular posts from this blog

What does second last employer means? [closed]

List of Gilmore Girls characters

One-line joke