代码之家  ›  专栏  ›  技术社区  ›  Ta Thanh Dinh

返回std::optional<T>,其中T的构造函数是私有的

  •  2
  • Ta Thanh Dinh  · 技术社区  · 4 月前

    我仍然不明白 std::optional 在以下代码中:

    class A
    {
    public:
      // A(int x, int y) : x(x), y(y) {} // always compiles
    private:
      A(int x, int y) : x(x), y(y) {}    // does not compile if using o.emplace(x, y)
      friend std::optional<A> makeA(int x, int y);
    
      int x, y;
    };
    
    std::optional<A> makeA(int x, int y)
    {
      std::optional<A> o;
      if (x != 0 && y != 0) {
        return A(x, y);
        // o.emplace(x, y);
      }
      return o;
    }
    

    如果我让构造函数 A 作为公众在 makeA(...) 我可以用 return A(x, y) o.emplace(x, y) ,两者都可以编译。

    但如果我让构造函数 A. 那么私人 o.位置(x,y) 不会编译。据我从阅读模板错误消息中了解到:

    error: no matching function for call to ‘std::optional<A>::emplace(int&, int&)’
       70 |     o.emplace(x, y);
          |     ~~~~~~~~~^~~~~~
    In file included from test.cpp:2:
    /usr/include/c++/11/optional:871:9: note: candidate: ‘template<class ... _Args> std::enable_if_t<is_constructible_v<_Tp, _Args ...>, _Tp&> std::optional<_Tp>::emplace(_Args&& ...) [with _Args = {_Args ...}; _Tp = A]’
      871 |         emplace(_Args&&... __args)
          |         ^~~~~~~
    /usr/include/c++/11/optional:871:9: note:   template argument deduction/substitution failed:
    In file included from /usr/include/c++/11/bits/move.h:57,
                     from /usr/include/c++/11/bits/stl_pair.h:59,
                     from /usr/include/c++/11/bits/stl_algobase.h:64,
                     from /usr/include/c++/11/memory:63,
                     from test.cpp:1:
    /usr/include/c++/11/type_traits: In substitution of ‘template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = A&]’:
    /usr/include/c++/11/optional:871:2:   required by substitution of ‘template<class ... _Args> std::enable_if_t<is_constructible_v<A, _Args ...>, A&> std::optional<A>::emplace<_Args ...>(_Args&& ...) [with _Args = {int&, int&}]’
    test.cpp:70:14:   required from here
    /usr/include/c++/11/type_traits:2579:11: error: no type named ‘type’ in ‘struct std::enable_if<false, A&>’
     2579 |     using enable_if_t = typename enable_if<_Cond, _Tp>::type;
          |           ^~~~~~~~~~~
    In file included from test.cpp:2:
    /usr/include/c++/11/optional:883:9: note: candidate: ‘template<class _Up, class ... _Args> std::enable_if_t<is_constructible_v<_Tp, std::initializer_list<_Up>&, _Args ...>, _Tp&> std::optional<_Tp>::emplace(std::initializer_list<_Up>, _Args&& ...) [with _Up = _Up; _Args = {_Args ...}; _Tp = A]’
      883 |         emplace(initializer_list<_Up> __il, _Args&&... __args)
          |         ^~~~~~~
    /usr/include/c++/11/optional:883:9: note:   template argument deduction/substitution failed:
    test.cpp:70:14: note:   mismatched types ‘std::initializer_list<_Tp>’ and ‘int’
       70 |     o.emplace(x, y);
    

    班级 A. 不可构建。但这怎么可能呢?

    2 回复  |  直到 4 月前
        1
  •  5
  •   463035818_is_not_an_ai    4 月前

    std::optional<A>::emplace 将其参数转发给 A 的构造函数。构造函数是私有的,因此无法被访问 emplace .你宣布 makeA 成为a friend 但这并不适用于由调用的其他函数 makeA 因此,出现了错误。

    你可以直接调用构造函数,因为 makeA 被宣布为a 朋友 属于 A. 因此,它可以访问私有构造函数。

        2
  •  4
  •   Marek R    4 月前

    对现有答案的小扩展。为了解决这个问题,您可以使用锁定键模式:

    class A {
        struct LockKey {
            explicit LockKey() { }
        };
    
    public:
        A(int x, int y, LockKey)
            : x(x)
            , y(y)
        {
        }
    
    private:
        friend std::optional<A> makeA(int x, int y);
    
        int x, y;
    };
    
    std::optional<A> makeA(int x, int y)
    {
        std::optional<A> o;
        if (x != 0 && y != 0) {
    #ifndef USE_EMPLACE
            return A(x, y, A::LockKey{});
    #else
            o.emplace(x, y, A::LockKey{});
    #endif
        }
        return o;
    }
    

    https://godbolt.org/z/ce9a38Phb