Подтвердить что ты не робот

Как напечатать адрес функции-члена в С++

Похоже, что std::cout не может печатать адрес функции-члена, например:

#include <iostream>

using std::cout;
using std::endl;

class TestClass
{
  void MyFunc(void);

public:
  void PrintMyFuncAddress(void);
};

void TestClass::MyFunc(void)
{
  return;
}

void TestClass::PrintMyFuncAddress(void)
{
  printf("%p\n", &TestClass::MyFunc);
  cout << &TestClass::MyFunc << endl;
}

int main(void)
{
  TestClass a;

  a.PrintMyFuncAddress();

  return EXIT_SUCCESS;
}

результат выглядит примерно так:

003111DB
1

Как распечатать адрес MyFunc с помощью std::cout?

4b9b3361

Ответ 1

Я не верю, что для этого есть какие-либо средства, предоставляемые языком. Есть перегрузки для operator << для потоков, чтобы печатать обычные указатели void*, но указатели функций-членов не могут быть конвертированы в void* s. Это все специфичные для реализации, но обычно указатели на функции-члены реализуются как пара значений - флаг, указывающий, является ли функция-член виртуальной, и некоторые дополнительные данные. Если функция является не виртуальной функцией, эта дополнительная информация обычно является фактическим адресом функции-члена. Если функция является виртуальной функцией, эта дополнительная информация, вероятно, содержит данные о том, как индексировать в таблицу виртуальных функций, чтобы найти функцию для вызова с учетом объекта получателя.

В общем, я думаю, это означает, что невозможно распечатать адреса функций-членов, не вызывая поведения undefined. Для достижения этого эффекта вам, вероятно, придется использовать какой-то трюк, специфичный для компилятора.

Надеюсь, это поможет!

Ответ 2

Я хотел бы добавить к другим ответам, что причина, по которой вы печатаете "1" вместо адреса, заключается в том, что по какой-то причине компилятор принуждает ваш указатель функции к логическому, так что вы действительно вызываете ostream& operator<< (bool val);

Это, кажется, не связано с тем, что функция является функцией-членом.

Вы можете открыть эту информацию с помощью clang++ -cc1 -ast-dump:

(ImplicitCastExpr 0x3861dc0 <col:13, col:25> '_Bool' <MemberPointerToBoolean>
    (UnaryOperator 0x3861940 <col:13, col:25> 'void (class TestClass::*)(void)' prefix '&'
        (DeclRefExpr 0x38618d0 <col:14, col:25> 'void (void)' CXXMethod 0x3861500 'MyFunc' 'void (void)')))))

Ответ 3

Один из способов сделать это (я не уверен, что он переносимый):

void TestClass::PrintMyFuncAddress(void)
{
  void (TestClass::* ptrtofn)() = &TestClass::MyFunc;
  cout << (void*&)ptrtofn<< endl;
}

рабочий пример: http://ideone.com/1SmjW

Ответ 4

Указатели на функции-члены также нуждаются в памяти. Они также имеют размер. Итак, как насчет печати памяти указателя:

template<typename R, typename T, typename... Args>
std::string to_string(R (T::*func)(Args...))
{
    union PtrUnion
    {
        R(T::*f)(Args...);
        std::array<unsigned char, sizeof(func)> buf;
    };
    PtrUnion u;
    u.f = func;

    std::ostringstream os;

    os << std::hex << std::setfill('0');
    for (auto c : u.buf)
        os << std::setw(2) << (unsigned)c;

    return os.str();
}

Вы можете использовать его следующим образом:

class TestClass
{
    void foo();
};

...

std::cout << to_string(&TestClass::foo) << std::endl;