c++c++14unique-ptrfriend-functionmsvc12

Error on MSVC when trying to declare std::make_unique as friend of my templated class


Apparently today, MSVC is trying its best to convince me to switch to clang. But I won't give up. Earlier I asked this question wondering how to declare std::make_unique as a friend of my class.

I got a pretty good answer on my simple scenario and indeed when I tried it with clang on wandbox it compiled just fine.

So I go happy back to Visual Studio 2013 to continue coding. A part of my code is this:

// other includes
#include <string>
#include <memory>

template <typename Loader, typename Painter, typename MeshT>
class Model
{
public:
    friend std::unique_ptr<Model> std::make_unique<Model>(
        const std::string&,
        const std::shared_ptr<Loader>&,
        const std::shared_ptr<Painter>&);

    // Named constructor
    static std::unique_ptr<Model> CreateModel(
        const std::string& filepath,
        const std::shared_ptr<Loader>& loader,
        const std::shared_ptr<Painter>& painter)
    {
        // In case of error longer than the Lord of the Rings trilogy, use the
        // line below instead of std::make_unique
        //return std::unique_ptr<Model>(new Model(filepath, loader, painter));
        return std::make_unique<Model>(filepath, loader, painter);
    }

// ...
protected:
    // Constructor
    Model(
        const std::string& filepath,
        const std::shared_ptr<Loader>& loader,
        const std::shared_ptr<Painter>& painter)
        : mFilepath(filepath)
        , mLoader(loader)
        , mPainter(painter)
    {
    }

// ...

};

Okay, to be honest I didn't expect to get it right on the first time but I was confident I could make some sense out of the error message:

1>d:\code\c++\projects\active\elesword\src\Model/Model.hpp(28): error C2063: 'std::make_unique' : not a function
1>          ..\..\src\Main.cpp(151) : see reference to class template instantiation 'Model<AssimpLoader,AssimpPainter,AssimpMesh>' being compiled

Apparently, MSVC doesn't think that the std::make_unique function is..well..a function.

The worst part is that I am tired and I got this feeling that I am missing something very very very (...) obvious. Can anyone help me unstuck?

Also, can anyone try this with Visual Studio 2015? Just out of curiosity..

Note: I know I could (and probably should) just use return std::unique_ptr<Model>(new Model(filepath, loader, painter)); but it just doesn't feel right.


Solution

  • Trying to friend std functions puts you in dangerous territory because you're making assumptions about their implementations that aren't guaranteed by the standard. For example, you want std::make_unique to be a friend so that it can access your protected constructor, but what if std::make_unique's implementation delegates this to some other secret function? What you'd need then is to befriend that secret function, but it's secret, so you can't.

    Other complications: Some forms of std::make_unique aren't exactly specified by the standard (though I don't think that applies to this exact example). Old versions of VC++ used macro magic to simulate variadic templates before the compiler had full support for variadic templates, so while there is a std::make_unqiue, it might not have the actual signature you expect.