【问题标题】:Appending ampersand to a class method将&符号附加到类方法
【发布时间】:2020-09-11 17:05:44
【问题描述】:

我遇到了一些 C++ 代码,大致如下:

        void (classA::*methodA)() const noexcept
        {
            &classA::methodB
        };

注意:显然我在这个例子中抽象出了类名和方法名。

methodA的目的是什么?

代码分析

  1. 它似乎引用了methodB,但没有括号,因此它似乎没有调用该方法
  2. 它使用与符号&,我读为take the address of
  3. 最后methodA 没有返回任何内容

总的来说,它似乎只是引用了address of 方法B。

有什么建议吗?

【问题讨论】:

  • 这不会编译,所以它的作用是有争议的。
  • 嗯,它确实为我编译。除非它隐藏在我看不到的一些#ifdef 后面。我也确实看到它被调用了。我可以尝试添加一个 printf 来查看它是否真的被调用了。
  • 您已经展示了 3 行代码。请发minimal reproducible example
  • 我们可以得到minimal reproducible example 吗?对我来说,这不应该编译为 classA::*methodA 不是成员指针或成员函数指针的正确语法。
  • 好的,抱歉。我将得到一个最小的可重现示例..

标签: c++ methods ampersand


【解决方案1】:

关键信息是您正在使用大括号初始化语法初始化指向成员函数 (PMF) 的指针。请参阅C++ FAQs on PMFs

这是您的代码说明和注释,用另一种方式来编写相同的东西,因为它使用类型别名,所以不太容易混淆:

#include <iostream>

// Declare a class with a non-static method
class classA 
{
public:
    void methodB() const noexcept { std::cout << "methodB\n"; }
};

int main()
{
    // Declare a function pointer by the name of methodA 
    // and initialize it to point to classA::methodB
    void (classA::*methodA)() const noexcept
    {
        &classA::methodB
    };

    // Create an instance of classA
    const auto a = classA{};

    // Call a method on our instance using the function pointer
    (a.*methodA)();
   
    ////////////////////////////////////////////////////////////////
    // A clearer equivalent of the above:

    // Declare an alias for the function pointer type
    using FnPtr = void (classA::*)() const noexcept;

    // Create an instance of the function pointer type,
    // also using brace initialization and pointing to `classA::methodB`
    const auto method = FnPtr{ &classA::methodB };

    // Call the function indirectly through the function pointer
    (a.*method)();    
}

Coliru 上实时查看,它会在此处打印:

methodB
methodB

如果您不需要知道类型(例如,它只是一个局部变量,而不是类的成员),一个更短的方法是您可以使用auto 来推断类型:

const auto someMethod = &classA::methodB;
(a.*someMethod)();    

如果您仍然不想键入该别名,但需要在无法使用 auto 的上下文中使用该类型,则可以使用 decltype 来声明它:

// Alias using decltype
using FnPtr = decltype( &classA::methodB );

// Declare instance using decltype (e.g., as a class member)
decltype( &classA::methodB ) method = nullptr;
// ... 
// set it later:
method = &classA::methodB;

// Define template param using decltype
auto fnPtrs = std::vector< decltype( &classA::methodB ) >{};

【讨论】:

  • 哦,哇,很好的答案。让我仔细回顾一下,但我认为它回答了我的问题。
  • 添加了一些关于使用 autodecltype 的脚注。
【解决方案2】:

有什么建议吗?

它定义了一个名为methodA的变量并将其初始化为&amp;classA::methodB

变量的类型是

指向classAconst 成员函数的指针,不带参数,返回void,并且该成员函数不抛出任何异常。

变量初始化为&amp;classA::methodB

如果你把它做成单线,那就是:

void (classA::*methodA)() const noexcept {&classA::methodB};

相当于:

void (classA::*methodA)() const noexcept = &classA::methodB;

【讨论】:

  • 谢谢!我认为这也回答了我的问题。让我查看其他答案并决定接受哪个答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-28
  • 2013-03-19
  • 2015-04-17
  • 1970-01-01
  • 1970-01-01
  • 2011-10-06
相关资源
最近更新 更多