将初始值设定项列表与返回引用的用户定义转换运算符一起使用时,将复制返回值
Return value is copied when using initializer list with a user-defined conversion operator that returns reference
我正试图围绕shared_ptr
编写一个包装器,它可以隐式地取消对底层类型的引用。代码如下:
#include <memory>
template<typename T>
class PtrWrapper {
public:
PtrWrapper(std::shared_ptr<T> ptr) : ptr_(ptr) {}
operator T& () {
return *ptr_;
}
T& ref() {
return *ptr_;
}
private:
std::shared_ptr<T> ptr_;
};
看起来没有什么问题。我尝试了几种使用包装器的方法:
#include <iostream>
class Nothing {
public:
Nothing() {
std::cout << "Construct " << this << std::endl;
}
Nothing(Nothing const& parent) {
std::cout << "Copy " << &parent << " " << this << std::endl;
}
Nothing(Nothing && parent) {
std::cout << "Move " << &parent << " " << this << std::endl;
}
~Nothing() {
std::cout << "Destruct " << this << std::endl;
}
};
int main() {
PtrWrapper<Nothing> wrapper{std::make_shared<Nothing>()};
// #1: OK
Nothing & by_assignment = wrapper;
// #2: OK
Nothing & by_operator{wrapper.operator Nothing &()};
// #3: OK
Nothing & by_function{wrapper.ref()};
// #4: OK
Nothing & by_initialization(wrapper);
// #5: Compile error: non-const lvalue reference to type 'Nothing' cannot bind to an initializer list temporary
// Nothing & by_initialization_2{wrapper};
// #6: The `Nothing` class is copied, which is not expected
Nothing const& by_initialization_3{wrapper};
return 0;
}
包装器类可以很好地进行赋值和圆括号初始化。
奇怪的是,当我试图用initializer list(上面代码中的#5和#6(初始化Nothing&
时,值被复制了,我必须对它使用const引用。然而,当我显式调用像wrapper.operator Nothing &()
(上面代码的#2(这样的转换运算符时,我得到了对第一行构造的原始对象的正确引用。
我读过cppreference,发现initializer列表是一个复制初始化的临时列表,但它不理解为什么当显式调用operator Nothing &()
时代码会工作。
有人能帮我弄清楚这里发生了什么吗?非常感谢!
您实际上是在这里进行引用初始化:
Nothing & by_initialization_2{wrapper};
规则规定,由于初始值设定项与绑定的引用的类型不同,因此会考虑用户定义的转换运算符,这很好,因为您有合适的转换运算符。
但是,如果转换函数返回的l值是通过一个大括号init列表传递的,那么一个临时值就会具体化。由于无法将非常数引用绑定到临时引用,因此初始化失败。
相关文章:
- 为什么常量词在重载运算符中不与 ostream 对象一起使用<<?
- 将 [][] 运算符与向量一起使用?
- 不能将重载比较运算符与 Catch 测试一起使用
- 当返回语句时,逗号运算符、大括号初始化列表和 std::unique_ptr 组合在一起
- 为什么我不能将运算符+与reverse_iterator一起使用?
- 将流运算符与Template类一起使用
- 让类与运算符一起工作更简单的方法
- 将运算符<<与隐式转换的非基本数据类型一起使用时出错
- 为什么重载运算符不与 std::string 一起使用 msvc /MD 标志
- #define 与运算符一起使用
- 将赋值运算符与make_pair方法一起使用会生成 CLion 警告
- 是否可以将引用类型别名与指针运算符一起使用来声明对指针的引用?
- 返回对象如何与分配运算符一起工作
- 将逻辑 OR 与 cout 运算符一起使用
- 如何将模运算符与其他数据类型一起使用
- 为什么在 sizeof() 函数中与 * 运算符一起使用和不使用 * 运算符时,指向结构变量的指针大小会有所不同?
- 将[]运算符与链接列表一起使用
- 将赋值运算符与 unique_ptr 向量一起使用
- 我可以将 std:fixed 或 std::setprecision() 与>>运算符一起使用吗?
- 在C++中,我们如何将插入运算符和其他运算符链接在一起