使用显式构造函数返回不可复制的不可移动对象

pep*_*er0 6 c++ c++11

如果我们有一个带有非显式构造函数的不可移动的非可复制类,我们可以返回它并使用如下(在C++ 11中):

#include <iostream>
class NonCop
{
public:
    /*non explicit*/ NonCop(int a, int b) : number(a + b) {}
    NonCop(const NonCop&) = delete;
    int number;
};

NonCop get_non_cop()
{
    return {1, 2};
}

int main()
{
    NonCop &&nc = get_non_cop();
    std::cout << "three: " << nc.number << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果构造函数是显式的,则它不起作用.有没有任何方法在C++ 11/C++ 14中执行此操作而不进行任何修改NonCop

目前我正在使用从NonCop派生的解决方法,使用"deexplicits"构造函数的包装器,但它看起来并不漂亮.

Yak*_*ont 6

不,这是不可能的.在没有隐式移动或复制(编译器肯定会忽略)的情况下从C++ 11或14中的函数返回时,没有机制可以调用显式构造函数.

在C++ 17中,您只需输入return NonCop(1,2);,由于"保证省略",它将不再需要移动或复制构造函数.


但这是C++,所以是的,我可以让您的代码无需额外开销.通过作弊,并返回不同的类型.

template<class T>
struct implicit_construct:T {
  template<class...Ts>
  implicit_construct(Ts&&...ts):
    T(std::forward<Ts>(ts)...) // note: this is an EXPLICIT construction
  {}
};

implicit_construct<NonCop> get_non_cop()
{
  return {1, 2};
}
Run Code Online (Sandbox Code Playgroud)

实例.

一个implicit_construct<NonCop>从派生NonCop,所以你可以存储在一个返回值NonCop&&.


如果你是NonCop自己写的,那么我要做的就是添加:

 struct explicit_construct_t {};
 // ...
 struct NonCop {
   // ...
   template<class...Ts>
   NonCop( explicit_construct_t, Ts&&...ts ):
     NonCop( std::forward<Ts>(ts)... )
  {}
  // ...
};
Run Code Online (Sandbox Code Playgroud)

这意味着您可以通过在其前面添加一个explicit_construct_t隐式调用它来调用显式构造函数:

NonCop get_non_cop() {
  return {explicit_construct_t{}, 1, 2};
}
Run Code Online (Sandbox Code Playgroud)


101*_*010 5

不幸的是,在这种情况下,您无法返回临时对象,因为在按值返回表达式中,编译器要求对象的复制构造函数可访问,即使该对象最终将被复制删除。但是,您可以返回一个std::unique_ptr而不是具体的对象。

std::unique_ptr<NonCop> get_non_cop() {
    return std::make_unique<NonCop>(1, 2);
}
Run Code Online (Sandbox Code Playgroud)

现场演示