Ошибка в MSVC при попытке объявить std::make_unique другом моего шаблонного класса

Судя по всему, сегодня MSVC изо всех сил пытается убедить меня перейти на clang. Но я не сдамся. Ранее я задавал этот вопрос интересно, как объявить std::make_unique как friend моего класса.

Я получил довольно хороший ответ на свой простой сценарий, и действительно, когда я попробовал его с clang на wandbox он скомпилирован просто отлично.

Так что я счастлив вернуться в Visual Studio 2013, чтобы продолжить кодирование. Часть моего кода такова:

// 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)
    {
    }

// ...

};

Ладно, если честно, я не ожидал, что с первого раза все получится, но был уверен, что смогу разобраться в сообщении об ошибке:

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

Судя по всему, MSVC не думает, что std::make_unique функция является... ну... функцией.

Хуже всего то, что я устал, и у меня такое чувство, что я упускаю что-то очень-очень (...) очевидное. Может ли кто-нибудь помочь мне расклеиться?

Кроме того, может ли кто-нибудь попробовать это с Visual Studio 2015? Просто из любопытства..

Примечание. Я знаю, что мог бы (и, вероятно, должен) просто использовать return std::unique_ptr<Model>(new Model(filepath, loader, painter));, но мне кажется, что это неправильно.


person TheCrafter    schedule 24.11.2015    source источник
comment
Не компилируется и на VS2015, и мне это кажется ошибкой MSVC. Кажется, он не выведет аргументы шаблона, вам нужно указать их явно. Поэтому, если я создам свой собственный невариативный make_unique, а затем изменю объявление друга на friend std::unique_ptr<A> my::make_unique<A, T&>(T&);, как в следующем примере, он скомпилируется в MSVC - coliru.stacked-crooked.com/a/a036bc575b552665   -  person Praetorian    schedule 25.11.2015
comment
Вам следует перестать пытаться подружиться с чем-то в стандартной библиотеке. В этом заключается безумие.   -  person T.C.    schedule 25.11.2015
comment
Praetorian: Хм, я надеялся, что в vs2015 не будет такой проблемы. Ну, я думаю, что лучше забыть об этом подходе, если я хочу, чтобы мой проект работал на всех компиляторах. Кстати, хороший обходной путь. Я могу использовать его или что-то в этом роде.   -  person TheCrafter    schedule 26.11.2015
comment
Обычный метод заключается в использовании общедоступного конструктора, для вызова которого требуется экземпляр закрытого типа тега.   -  person T.C.    schedule 27.11.2015


Ответы (1)


Попытка подружить стандартные функции ставит вас на опасную территорию, потому что вы делаете предположения об их реализации, которые не гарантируются стандартом. Например, вы хотите, чтобы std::make_unique был другом, чтобы он мог получить доступ к вашему защищенному конструктору, но что, если реализация std::make_unique делегирует это какой-то другой секретной функции? Тогда вам нужно подружиться с этой секретной функцией, но она секретная, поэтому вы не можете.

Другие сложности: некоторые формы std::make_unique точно не указаны в стандарте (хотя я не думаю, что это применимо к этому конкретному примеру). Старые версии VC++ использовали магию макросов для имитации вариативных шаблонов до того, как компилятор получил полную поддержку вариативных шаблонов, поэтому, несмотря на наличие std::make_unqiue, он может не иметь фактической подписи, которую вы ожидаете.

person Adrian McCarthy    schedule 25.11.2015
comment
Да, это имеет абсолютный смысл. Ты прав. Спасибо за Ваш ответ! - person TheCrafter; 26.11.2015