调用C++中隐式转换可以到达的成员函数

问题描述 投票:0回答:2

尝试创建一个类似于 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 但失败并出现相同的编译错误。

c++ implicit-conversion reference-wrapper
2个回答
2
投票

获得此类行为的一种方法是重载箭头运算符

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

您可以在这个现场示例中看到它的工作原理。


0
投票

你问了

为什么在包装对象上调用 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]。

尾注]

请注意,在点运算符中使用对象不是其中之一。

© www.soinside.com 2019 - 2024. All rights reserved.