【问题标题】:How to make std::make_unique a friend of my class如何让 std::make_unique 成为我班的朋友
【发布时间】:2016-02-27 13:34:21
【问题描述】:

我想将std::make_unique 函数声明为我班级的朋友。原因是我想声明我的构造函数protected 并提供另一种使用unique_ptr 创建对象的方法。这是一个示例代码:

#include <memory>

template <typename T>
class A
{
public:
    // Somehow I want to declare make_unique as a friend
    friend std::unique_ptr<A<T>> std::make_unique<A<T>>();


    static std::unique_ptr<A> CreateA(T x)
    {
        //return std::unique_ptr<A>(new A(x)); // works
        return std::make_unique<A>(x);         // doesn't work
    }

protected:
    A(T x) { (void)x; }
};

int main()
{
    std::unique_ptr<A<int>> a = A<int>::CreateA(5);
    (void)a;
    return 0;
}

现在我收到此错误:

Start
In file included from prog.cc:1:
/usr/local/libcxx-head/include/c++/v1/memory:3152:32: error: calling a protected constructor of class 'A<int>'
return unique_ptr<_Tp>(new _Tp(_VSTD::forward<_Args>(__args)...));
                           ^
prog.cc:13:21: note: in instantiation of function template specialization 'std::__1::make_unique<A<int>, int &>' requested here
    return std::make_unique<A>(x);     // doesn't work
                ^
prog.cc:22:41: note: in instantiation of member function 'A<int>::CreateA' requested here
std::unique_ptr<A<int>> a = A<int>::CreateA(5);
                                    ^
prog.cc:17:5: note: declared protected here
A(T x) { (void)x; }
^
1 error generated.
1
Finish

std::make_unique 声明为我班的朋友的正确方法是什么?

【问题讨论】:

  • 尝试使用 clang 编译 - 它抱怨:main.cpp:17:39: error: friends can only be classes or functions - friend std::unique_ptr> std::make_unique>();` 错误位置是模板实例化。
  • 有趣的是,带有 -std=c++14 的编译器和这个消失了,错误指向下面@Praetorian 的答案。
  • @marko 上述错误与 clang 有关。我现在在 MSVC(与 2013 年相比)。那里也不行。
  • 好的。我的坏 - 不同的标准版本。除了这个技巧很难实现之外,我质疑这作为一种合同设计 - 看起来你在这里混淆而不是分离关注点。
  • 我同意这个建议,因为它依赖于实现并且你不能依赖它工作。可能是重新设计的时候了:/

标签: c++ templates c++14 unique-ptr friend-function


【解决方案1】:

make_unique 完美转发你传递给它的参数;在您的示例中,您将左值 (x) 传递给函数,因此它会将参数类型推断为 int&amp;。您的 friend 函数声明需要是

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

同样,如果您要在 CreateA 中使用 move(x),则需要使用 friend 声明

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

这会将代码发送到compile,但绝不保证它会在另一个实现上编译,因为据您所知,make_unique 将其参数转发给另一个内部帮助函数,该函数实际实例化您的类,在这种情况下,助手需要是friend

【讨论】:

  • 确实有效!但是,如果我想向构造函数传递更多参数怎么办?例如,如果我的构造函数是A(const std::string&amp; str1, const std::shared_ptr&amp; ptr1),它比整数更复杂。
  • @TheCrafter 我认为您必须与相应的make_unique 签名成为朋友,我认为您不会变得更通用,因为不允许函数模板的部分专业化。我的建议是忘记make_unique 并让CreateA 返回unique_ptr&lt;A&gt;(new A(...))。与make_shared 不同,make_unique 不会给您带来太多优势。
  • 好的,我知道了。我只是想知道是否有解决方法!谢谢你的回答:)
  • 不允许使用可变模板朋友吗?
  • @paulm 是的,一般来说是possible。但是在这种情况下,如果你写template&lt;typename... Args&gt; friend std::unique_ptr&lt;A&gt; std::make_unique&lt;A&gt;(Args&amp;&amp;...);,那就是函数模板的部分特化,这是不允许的。
猜你喜欢
  • 2011-03-23
  • 1970-01-01
  • 1970-01-01
  • 2012-01-27
  • 1970-01-01
  • 2021-03-21
  • 1970-01-01
  • 1970-01-01
  • 2016-02-27
相关资源
最近更新 更多