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.
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.