我正在使用GCC 4.8编译以下代码:
#include <memory>
template<typename T, typename ...Args>
std::unique_ptr<T> make_unique(Args&& ...args) {
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
struct S {
template<class... Args>
static std::unique_ptr<S> create(Args&&... args) {
return make_unique<S>(std::forward<Args>(args)...);
}
private: // if I remove this line, then the compilation is OK
S(int) {}
S() = default;
};
int main() {
auto s1 = S::create(); // OK
auto s2 = S::create(0); // Compilation error
}
有人能解释一下编译器出错的原因吗?
main.cpp:实例化'std :: unique_ptr make_unique(Args&amp;&amp; ......)[T = S; Args = {int}]':
main.cpp:11:58:'static std :: unique_ptr需要 S :: create(Args&amp;&amp; ...)[与Args = {int}]'
main.cpp:20:26:从这里要求
main.cpp:14:5:错误:'S :: S(int)'是私有的
S(int) {} ^
main.cpp:5:65:错误:在此上下文中 return std :: unique_ptr(new T {std :: forward(args)...});
^
答案 0 :(得分:11)
有人能解释一下编译器出错的原因吗?
将int
的构造函数声明为private
,这就是它给出编译错误的原因。请注意,构造函数是从make_unique
(无权访问私有成员)而不是create
调用的。
但是,您可能想知道为什么第一次调用create()
编译得很好,我认为这是因为 GCC有错误。即使在这种情况下也不应该编译,因为默认构造函数也被声明为private
。 Clang正确地为两次调用都提供了错误(see this)。
无论如何,如果你想让他们private
,请让make_unique
成为班上的朋友。
答案 1 :(得分:4)
原因很简单:
不是从S::create
内部调用构造函数,而是从::make_unique
函数模板中调用,该函数模板无法访问私有成员函数S::S(int)
。
一个简单的解决方法是自己致电new
(参见here)。
实际上,更有趣的问题是为什么它在第一次通话时也没有错误......
答案 2 :(得分:2)
在C ++ struct中,默认情况下所有成员都是公共的。在类声明中,默认情况下成员是私有的。在你的情况下,构造函数已被设为私有,这就是你得到错误的原因:S :: S(int)是私有的
因此,请将更改设为:
public:
S(int) {}
S() = default;
答案 3 :(得分:2)
如果你想让这个类的构造函数保密,你必须让任何非成员用户(这里:make_unique
)成为朋友:
struct S {
template<typename T, typename ...Args>
friend std::unique_ptr<T> make_unique(Args&& ...args);
// rest as before
};
或者,您可以避免make_unique<>
并直接从静态成员创建unique_ptr<S>
:
struct S {
template<class... Args>
static std::unique_ptr<S> create(Args&&... args)
{ return std::unique_ptr<S>(new S{std::forward<Args>(args)...}); }
// rest as before
};
答案 4 :(得分:1)
如果某个构造函数是私有的,则意味着除了类本身(和朋友)之外,没有人能够使用该构造函数创建它的实例。
要创建只具有私有构造函数的类的实例,必须使用静态方法。