为什么会出现编译错误?

时间:2014-04-23 10:09:17

标签: c++ templates c++11

我正在使用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)...});

                                                             ^

5 个答案:

答案 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)

如果某个构造函数是私有的,则意味着除了类本身(和朋友)之外,没有人能够使用该构造函数创建它的实例。

要创建只具有私有构造函数的类的实例,必须使用静态方法。