-2

Here is an example of my code:

#include <iostream>
#include <memory>

class Base
{
public:
  virtual void name() = 0;
};

using ptr_t = std::unique_ptr<Base>;

class A : public Base
{
  A(int x) : n(x) {}

public:
  void name() override
  {
    std::cout << "Test " << n << "\n";
  }

  template <typename T>
  friend ptr_t create(int x);

private:
  int n;
};

template <typename T>
ptr_t create(int x)
{
  return std::make_unique<T>(x);
}

int main()
{
  auto a = create<A>(3);
  a->name();
}

At first I thought the problem was in the conversion from std::unique_ptr<A> to std::unique_ptr<Base>. But that seems to work fine in an isolated code sample and is also correct according to this answer: unique_ptr to a base class

The code above also works if I use a raw pointer instead of a unique pointer.

Can someone explain what I'm missing. Thank you.

katrasnikj
  • 3,151
  • 3
  • 16
  • 27
  • 4
    Look at the signature of your function declaration again. :) – Rakete1111 Nov 20 '17 at 16:04
  • I apologize for posting an incomplete code sample. I have updated the code sample and improved the description of the problem. Please reopen the question @Rakete1111 – katrasnikj Nov 21 '17 at 09:42
  • 1
    I'd like to but it seems like your code [compiles just fine](https://godbolt.org/g/pfQbdh)... – Rakete1111 Nov 21 '17 at 19:21
  • Huh, that's interesting. I'm using the MSVC 15.0 compiler (Visual Studio 2017). I get the same error as with this online compiler http://rextester.com/YXPKUO5666 – katrasnikj Nov 21 '17 at 19:42
  • 1
    Probably a compiler bug that was fixed later on. goldbolt uses 19.10.25017, while yours uses a slightly older one and it compiles just fine [for me](https://godbolt.org/g/3GYefY). – Rakete1111 Nov 21 '17 at 20:21

1 Answers1

2

Be careful, the signature of your friend function needs to match its implementation:

class A
{
  A() {}

  template <typename T>
  friend T* create();
};

template <typename T>
T* create()
{
    return new T;
}

int main()
{
    auto a = create<A>();
}

Updated to your new question. You need to friend make_unique, it is the function accessing to the constructor. But why do you need templates? This works for me:

#include <iostream>
#include <memory>

class Base
{
public:
  virtual void name() = 0;
};


class A final : public Base
{
  A(int x) : n(x) {}

public:
  void name() override
  {
    std::cout << "Test :" << n << "\n";
  }

  friend std::unique_ptr<A> std::make_unique<A>(int& x);

private:
  int n;
};

std::unique_ptr<A> create(int x)
{
  return std::make_unique<A>(x);
}

int main()
{
  auto a = create(3);
  a->name();

}
Blasco
  • 1,607
  • 16
  • 30