尝试创建一个类似于 std::reference_wrapper 的引用包装器,但可以调用被包装对象的方法。
#include <iostream>
class A {
public:
void f() {
std::cout << "A::f()\n";
}
};
class WrapA {
public:
WrapA(A& a) : _a_ptr{&a} {}
operator A&() {
return *_a_ptr;
}
private:
A* _a_ptr;
};
int main() {
A a;
WrapA wrap{a};
wrap.f(); // Fails with compile error: ‘class WrapA’ has no member named ‘f’
static_cast<A>(wrap).f(); // Works
return 0;
}
为什么在包装对象上调用 A 类函数 f() 不起作用,尽管可以从 WrapA 到 A 隐式转换?有什么办法可以解决这个问题吗?
尝试使用 std::reference_wrapper 但失败并出现相同的编译错误。
获得此类行为的一种方法是重载箭头运算符
operator ->
并让它返回指向包装对象的指针。编译器将递归地应用到返回的指针上,并让您调用成员函数。那会给你
#include <iostream>
class A {
public:
void f() {
std::cout << "A::f()\n";
}
};
class WrapA {
public:
WrapA(A& a) : _a_ptr{&a} {}
A* operator ->() {
return _a_ptr;
}
private:
A* _a_ptr;
};
int main() {
A a;
WrapA wrap{a};
wrap->f();
return 0;
}
输出
A::f()
您可以在这个现场示例中看到它的工作原理。
你问了
为什么在包装对象上调用 A 类函数 f() 不起作用,尽管可以从 WrapA 到 A 隐式转换?
该标准指定了可以进行隐式转换的上下文(https://timsong-cpp.github.io/cppwp/n4140/conv#2):
2 [注意:给定类型的表达式将在多个上下文中隐式转换为其他类型:
(2.1) -- 用作运算符的操作数时。运算符对其操作数的要求决定了目标类型(子句 [expr])。
(2.2) -- 当用在 if 语句或迭代语句的条件中时([stmt.select]、[stmt.iter])。目标类型是 bool。
(2.3) -- 当用在 switch 语句的表达式中时。目标类型是整数([stmt.select])。
(2.4) -- 当用作初始化的源表达式时(包括用作函数调用中的参数和用作 return 语句中的表达式)。正在初始化的实体的类型(通常)是目标类型。请参阅 [dcl.init]、[dcl.init.ref]。
—尾注]
请注意,在点运算符中使用对象不是其中之一。