gpt4 book ai didi

c++ - 具有右值引用成员的通用复制构造函数

转载 作者:搜寻专家 更新时间:2023-10-31 01:47:34 24 4
gpt4 key购买 nike

我正在开发一个简单的包装器模板类,它在调用特殊成员函数时进行记录。这些函数不能默认,因为它们执行额外的日志记录相关任务。

template <typename T>
struct logger {
logger(T const& value) : value_(value) { /*...log...*/ }
logger(T&& value) : value_(std::move(value)) { /*...log...*/ }
logger(logger const& other) : value_(other.value_) { /*...log...*/ }
logger(logger&& other) : value_(std::move(other.value_)) { /*...log...*/ }

T value_;
};

不幸的是,当包装类型是rvalue-reference时,copy-constructor 无法编译并显示以下错误消息:

error: cannot bind ‘int’ lvalue to ‘int&&’

原因是隐式复制构造函数对于右值引用成员的行为会有些不同:

[class.copy 12.8/15] The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move of its bases and members. [...] Let x be either the parameter of the constructor or, for the move constructor, an xvalue referring to the parameter. Each base or non-static data member is copied/moved in the manner appropriate to its type:

  • if the member is an array, each element is direct-initialized with the corresponding subobject of x;
  • if a member m has rvalue reference type T&&, it is direct-initialized with static_cast<T&&>(x.m);
  • otherwise, the base or member is direct-initialized with the corresponding base or member of x.

这让我想到了我的问题:如何编写一个通用的复制构造函数,它的行为就像一个隐式定义的复制构造函数,即使在使用时也是如此右值引用作为成员。

对于这种特殊情况,我可以为右值引用 添加额外的特化。但是,我正在寻找一种不限于单个成员且不引入代码重复的通用解决方案。

最佳答案

这里有龙。

logger(logger const& other) : value_(other.value_)

表达式other.value_T const 类型的左值,例如int& , int&&int const .

  1. 如果 T == int&& , 你需要做一个 move ,因为表达式是左值。 move相当于 static_cast<int&&> , 所以你可以做 static_cast也可以直接。

  2. 如果 T == int& ,不需要转换。

  3. 如果 T == int ,不需要转换。

对于定义为的复制构造函数:

logger(logger const& other) : value_(static_cast<T>(other.value_)) {/*...*/}

适用于第三种情况,这被定义为临时的引入,并可能导致额外的复制/移动,尽管我认为它可以并且将会被省略。

不依赖复制/移动省略的解决方案是引入 weird_cast ,在任何情况下都会产生所需的类型:

#include <type_traits>

template<class T, class U>
typename std::enable_if<std::is_reference<T>{}, T>::type
weird_cast(U& p)
{
return static_cast<T>(p);
}

template<class T, class U>
typename std::enable_if<not std::is_reference<T>{}, T const&>::type
weird_cast(U const& p)
{
return p;
}

int main()
{
int o = 42;
int & lo = o;
int && ro = std::move(o);
int const lco = o;

int&& r = weird_cast<int&&>(ro);
int& l = weird_cast<int& >(lo);
int d = weird_cast<int >(lco);
}

这类似于 std::forward , 但也支持“转发”非引用类型。


龙在哪里?

[class.copy]/11 指定:

A defaulted copy/move constructor for a class X is defined as deleted if X has:

  • [...]
  • for the copy constructor, a non-static data member of rvalue reference type
  • [...]

右值引用通常绑定(bind)到一个 xvalue 或 prvalue,即绑定(bind)到一个引用“接近其生命周期结束”的对象的表达式。由于生命周期不会通过函数边界得到延长,因此允许这样的“复制”很容易出错。

关于c++ - 具有右值引用成员的通用复制构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19040518/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com