显然今天,MSVC 正在尽力说服我改用 clang。但我不会放弃。早些时候我问过这个问题想知道如何声明
std::make_unique
为我班级的friend
。
我在简单的场景中得到了一个很好的答案,事实上,当我在 wandbox 上使用 clang 进行尝试时,它编译得很好。
所以我很高兴回到 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
function 是..嗯..一个函数。
最糟糕的是我很累,我感觉我错过了一些非常非常非常(...)明显的东西。谁能帮我解开吗
另外,任何人都可以使用 Visual Studio 2015 尝试这个吗?只是出于好奇..
注意:我知道我可以(并且可能应该)只使用
return std::unique_ptr<Model>(new Model(filepath, loader, painter));
,但感觉不太对。
尝试与 std 函数交友会让您陷入危险境地,因为您对它们的实现做出了标准无法保证的假设。例如,您希望 std::make_unique 成为友元,以便它可以访问受保护的构造函数,但如果 std::make_unique 的实现将其委托给其他秘密函数怎么办?那么你需要的是与那个秘密函数成为朋友,但它是秘密的,所以你不能。
其他复杂情况:某些形式的 std::make_unique 并未由标准完全指定(尽管我认为这不适用于这个确切的示例)。在编译器完全支持可变参数模板之前,旧版本的 VC++ 使用宏魔法来模拟可变参数模板,因此虽然存在 std::make_unqiue,但它可能没有您期望的实际签名。
一个问题是不同的编译器可能以不同的方式实现 std::make_unique 。例如。
friend unique_ptr<T> make_unique(Args&...);
不适用于 Visual Studio 17.7.1 或 GCC 13.2。这是两个略有不同的工作朋友。
#include <iostream>
#include <memory>
class classA {
public:
class classB {
friend classA;
#ifdef _MSC_VER
// Works in Visual Studio 17.7.1 /std:c++20
template<class _Ty, class... _Types, std::enable_if_t<!std::is_array_v<_Ty>, int> >
friend std::unique_ptr<_Ty> std::make_unique(_Types&&...);
#else
// Works in GCC 13.2. -std=c++20
template<typename _Tp, typename... _Args>
friend std::__detail::__unique_ptr_t<_Tp> std::make_unique(_Args&&...);
#endif
public:
classB() {}
private:
classB(const std::string& str) : mVal(str) {}
std::string mVal;
};
std::unique_ptr<classB> make_classB() {
return std::make_unique<classB>("Hello");
}
};
int main() {
classA a;
auto b = a.make_classB();
}
问候