You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

私有构造函数下std::optional的emplace调用编译失败问题问询

为什么std::optional::emplace无法访问类的private构造函数?

当类A的构造函数设为public时,makeA函数中使用return A(x, y)或o.emplace(x, y)均可编译通过;但将构造函数设为private后,o.emplace(x, y)无法编译,编译器提示类A不可构造。

示例代码

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

编译错误信息

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

原因解析

核心问题出在友元权限的作用范围和模板类型检查的上下文:

  • makeA是类A的友元,因此在makeA内部直接调用A(x, y)构造对象是合法的。返回这个对象给std::optional<A>时,optional只需要执行移动/拷贝构造(而非直接构造A),这一步不需要访问A的私有构造函数。
  • std::optional::emplace的实现依赖std::is_constructible_v<A, int&, int&>类型特性检查,这个检查是在std命名空间的模板代码中进行的——std::optional的成员函数不在A的友元列表里,无法看到A的私有构造函数,导致is_constructible_v返回false,触发enable_if的SFINAE规则,最终emplace函数被排除在候选列表之外,编译失败。

解决建议

如果想在私有构造的场景下使用emplace,可以尝试将std::optional<A>的emplace成员函数设为A的友元,但这会依赖具体标准库实现,通用性较差;更稳妥的方式是保持return A(x, y)的写法,直接构造A对象后返回给optional。

内容的提问来源于stack exchange,提问作者Konstante

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 12:47:38