【问题标题】:Why do I get a compilation error?为什么会出现编译错误?
【发布时间】:2014-06-08 02:26:40
【问题描述】:

我正在使用 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&& ...) [与 T = S; Args = {int}]':

main.cpp:11:58: 来自'static std::unique_ptr S::create(Args&& ...) [with 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)...});

                                                             ^

【问题讨论】:

    标签: c++ templates c++11


    【解决方案1】:

    谁能解释一下编译器出现这个错误的原因?

    采用int 的构造函数被声明为private,这就是它给出编译错误的原因。请注意,构造函数是从 make_unique(它无权访问私有成员)调用的,而不是从 create 调用的。

    但是,您可能想知道为什么对create() 的第一次调用编译得很好,我认为这是因为GCC 有错误。即使在这种情况下也不应该编译,因为默认构造函数也被声明为privateClang 正确地给出了两个调用的错误 (see this)。

    无论如何,如果您想保留他们private,请让make_unique 成为班级的朋友。

    【讨论】:

      【解决方案2】:

      原因很简单:

      构造函数不是从S::create内部调用的,而是从::make_unique函数模板内部调用的,它不能访问私有成员函数S::S(int)

      一个简单的解决方法是自己致电new(请参阅here)。

      其实更有趣的问题是为什么它在第一次调用时也不会出错...

      【讨论】:

      • 我认为 OP 的问题是他(相当合理!)希望避免在代码中显式调用 new
      【解决方案3】:

      在 C++ 结构中,默认情况下所有成员都是公共的。在类声明中,成员默认是私有的。在您的情况下,构造函数已设为私有,这就是您收到错误的原因:S::S(int) was private

      所以,修改如下:

      public: 
          S(int) {}
          S() = default;
      

      【讨论】:

      • 我不想公开构造函数。这就是我引入create()的原因,此外,由于某些原因,私有S()构造函数在私有时不会使编译失败,而S(int)会使编译失败...
      【解决方案4】:

      如果你想让类的构造函数保持私有,你必须让任何非成员用户(这里:make_unique)成为朋友:

      struct S {
        template<typename T, typename ...Args>
        friend std::unique_ptr<T> make_unique(Args&& ...args);
        // rest as before
      };
      

      或者,您可以避免使用make_unique&lt;&gt;,直接从静态成员创建unique_ptr&lt;S&gt;

      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
      };
      

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          猜你喜欢
          • 2014-10-11
          • 2018-11-29
          • 1970-01-01
          • 2011-07-10
          • 1970-01-01
          • 2011-12-27
          • 2023-03-30
          • 1970-01-01
          • 2013-08-14
          相关资源
          最近更新 更多