Any reason why this does not compile in Visual Studio C++? I'm using Visual Studio 2017 15.7.1. It compiles in clang and g++:
#include <utility>
#include <vector>
struct Foo {
Foo(int x) {}
Foo(Foo const& b) {}
};
struct Bar {
template <class... Args>
Bar(Args&&... args)
: foo(std::forward<Args>(args)...) {}
Foo foo;
};
void test() {
std::vector<Bar> v;
v.emplace_back(123);
}
The error is error C2664: 'Foo::Foo(const Foo &)': cannot convert argument 1 from 'Bar' to 'int'
See https://godbolt.org/g/bKb34v
EDIT: I've submitted this issue here: https://developercommunity.visualstudio.com/content/problem/252470/perfect-forwarding-compiler-bug.html
This is your bug, not MSVC's.
Foo
's copy constructor is not noexcept
and it has no move constructor.Bar
's implicitly declared move constructor is not noexcept
either, because it needs to call the aforementioned copy constructor for the Foo
data member.emplace_back
may reallocate, and since Bar
appears copyable, that reallocation will copy the existing elements to preserve the strong exception safety guarantee.const
or non-const
Bar
lvalue.Bar
lvalue.The fix is to constrain the constructor template so that it doesn't hijack. For example:
template <class... Args,
class = std::enable_if_t<std::is_constructible_v<Foo, Args...>>>
Bar(Args&&... args)
: foo(std::forward<Args>(args)...) {}
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