2

Consider the following code snippet

#include <memory>

struct A {
    int x, y;
};

struct B{
    A a;

    B(A a): a(a) {}
};

int main() {
    // Ok
    B({2,3});

    // Ok
    auto ptr = new B({2,3});

    // Ok
    auto ptr_2 = std::make_unique<B>(A{2, 3});

    // Error
    auto ptr_3 = std::make_unique<B>({2, 3});
}

When initializing a B object in the first two ways, one can create a temporary A constructor parameter without naming the type and the compiler can figure out what it represents and what constructor it should call.

However, std::make_unique fails to compile without explicitly naming the type of the parameter. According to cppreference, the function call is equivalent to

unique_ptr<T>(new T(std::forward<Args>(args)...))

I had expected the call with std::forward to be equivalent to new B({2,3});, but that is not the case on the compilers I tested, namely gcc and clang trunk. Are they wrong? If not, why does forwarding the arguments not work as I expected?

patatahooligan
  • 3,111
  • 1
  • 18
  • 27
  • 3
    `{2, 3}` has no type, so template deduction fail. – Jarod42 Feb 21 '20 at 12:12
  • Unfortunately, this is how C++ works (or doesn't work, in the eye of the beholder). As you've correctly pointed out, this construct uses universal references, which cannot bind to type-less braced initialization lists. See the linked question for more information. – Sam Varshavchik Feb 21 '20 at 12:14
  • @SamVarshavchik So it is the `std::forward` call itself that fails and it has nothing to do with the constructor? Still, could it not be forwarded as an initializer list or some special type which could then be used at the call site if appropriate? – patatahooligan Feb 21 '20 at 12:22
  • There's nothing wrong with the constructor. – Sam Varshavchik Feb 21 '20 at 12:52

0 Answers0