Как напечатать адрес функции-члена в С++
Похоже, что 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
?
Ответы
Ответ 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;