是否可以修复打印为 1 或 true 的 iostream cout/cerr 成员函数指针?
Is possible to fix the iostream cout/cerr member function pointers being printed as 1 or true?
如果您运行以下情况:
#include <iostream>
int main()
{
std::cout.setf(std::ios::boolalpha);
std::cout << &main << "\n";
std::cout << (void*)&main << "\n"; // The workaround
return 0;
}
// prints something like
// true
// 0x55deee04189a
如果删除 std::cout.setf(std::ios::boolalpha)
调用,它只会打印 1
而不是 true
。
如果您查看 https://godbolt.org/z/6CFH3P 程序集,您会注意到 C++
模板解析正在选择布尔运算符 std::basic_ostream<char, std::char_traits<char> >::operator<<(bool)
。
经过搜索,我找到了问题的解决方案How to print function pointers with cout?
The C++ Standard specifies:
4.12 Boolean conversions
1 An rvalue of arithmetic,
enumeration, pointer, or pointer to
member type can be converted to an
rvalue of type bool.
这是为函数指针指定的唯一转换。
但是,它不适用于成员class函数指针:https://godbolt.org/z/zBN5Va
#include<iostream>
template<class Ret, class... Args>
std::ostream& operator <<(std::ostream& os, Ret(*p)(Args...) ) {
return os << "funptr " << (void*)p;
}
struct test_debugger { void var() {} };
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}
int main() {
std::cout << "0. " << &test_debugger::var << std::endl;
std::cout << "1. " << fun_void_void << std::endl;
std::cout << "2. " << fun_void_double << std::endl;
std::cout << "3. " << fun_double_double << std::endl;
}
// Prints:
// 0. 1
// 1. funptr 0x100401080
// 2. funptr 0x100401087
// 3. funptr 0x100401093
是否可以修复 iostream cout/cerr 成员函数指针打印为 1 或 true 的问题?目标是使用任何自由函数或成员 class 函数,而无需在将它们发送到 std::cout
或 std::cerr
.[=32 之前手动将它们转换为 (void *)
指针=]
相关问题:
- Printing a pointer with <iostream>
- Pointer to member function, always prints as "1"
更新
我尝试关注 Dan M. tip (generic member function pointer as a template parameter):
template <typename T, typename R, typename ...Args>
std::ostream& operator <<(std::ostream& os, R (T::*p)(Args...) ) {
return os << "funptr " << (void*)p;
}
但它抛出了这个警告:https://godbolt.org/z/yj52hM
$ g++ -o main.exe --std=c++11 test_debugger.cpp && ./main.exe
test_debugger.cpp: In instantiation of ‘std::ostream& operator<<(std::ostream&, R (T::*)(Args ...)) [with T = test_debugger; R = int; Args = {}; std::ostream = std::basic_ostream<char>]’:
test_debugger.cpp:19:42: required from here
test_debugger.cpp:10:31: warning: converting from ‘int (test_debugger::*)()’ to ‘void*’ [-Wpmf-conversions]
return os << "funptr " << (void*)p;
^~~~~~~~
0. funptr 0x100401860
1. funptr 0x100401080
2. funptr 0x100401087
3. funptr 0x100401093
如何正确修复警告 warning: converting from ‘int (test_debugger::*)()’ to ‘void*’ [-Wpmf-conversions]
?
您的重载仅适用于函数指针,因为参数是函数指针。
它不适用于成员函数指针,因为成员函数指针不是函数指针,尽管这可能会造成混淆。您可以对成员函数指针使用类似的重载:
template<class C, class Ret, class... Args>
std::ostream& operator <<(std::ostream& os, Ret (C::*p)(Args...)) {
return os << "memfunptr " << "something...";
}
但是,成员函数指针不能转换为 void*
,因此您不能使用 void*
打印它们。您需要决定要在他们的案例中打印什么。如果您的目标只是获得一些可能与所指向的成员函数相关的输出,那么您可以执行以下操作:
unsigned char* internal_representation = reinterpret_cast<unsigned char*>(&p);
for(std::size_t i = 0; i < sizeof p; i++)
os << std::hex << (int)internal_representation[i];
P.S。在所有系统上也不允许将函数指针转换为 void*
。这是一个有条件支持的功能。它可能适用于至少使用动态链接的所有系统。
P.P.S。向标准 class 添加重载,其中所有参数都是标准 classes 或基本类型可能与未来的语言标准不兼容。
P.P.P.S。技术上不允许使用 main
地址。
如果您运行以下情况:
#include <iostream>
int main()
{
std::cout.setf(std::ios::boolalpha);
std::cout << &main << "\n";
std::cout << (void*)&main << "\n"; // The workaround
return 0;
}
// prints something like
// true
// 0x55deee04189a
如果删除 std::cout.setf(std::ios::boolalpha)
调用,它只会打印 1
而不是 true
。
如果您查看 https://godbolt.org/z/6CFH3P 程序集,您会注意到 C++
模板解析正在选择布尔运算符 std::basic_ostream<char, std::char_traits<char> >::operator<<(bool)
。
经过搜索,我找到了问题的解决方案How to print function pointers with cout?
The C++ Standard specifies:
4.12 Boolean conversions
1 An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool.
这是为函数指针指定的唯一转换。
但是,它不适用于成员class函数指针:https://godbolt.org/z/zBN5Va
#include<iostream>
template<class Ret, class... Args>
std::ostream& operator <<(std::ostream& os, Ret(*p)(Args...) ) {
return os << "funptr " << (void*)p;
}
struct test_debugger { void var() {} };
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}
int main() {
std::cout << "0. " << &test_debugger::var << std::endl;
std::cout << "1. " << fun_void_void << std::endl;
std::cout << "2. " << fun_void_double << std::endl;
std::cout << "3. " << fun_double_double << std::endl;
}
// Prints:
// 0. 1
// 1. funptr 0x100401080
// 2. funptr 0x100401087
// 3. funptr 0x100401093
是否可以修复 iostream cout/cerr 成员函数指针打印为 1 或 true 的问题?目标是使用任何自由函数或成员 class 函数,而无需在将它们发送到 std::cout
或 std::cerr
.[=32 之前手动将它们转换为 (void *)
指针=]
相关问题:
- Printing a pointer with <iostream>
- Pointer to member function, always prints as "1"
更新
我尝试关注 Dan M. tip (generic member function pointer as a template parameter):
template <typename T, typename R, typename ...Args>
std::ostream& operator <<(std::ostream& os, R (T::*p)(Args...) ) {
return os << "funptr " << (void*)p;
}
但它抛出了这个警告:https://godbolt.org/z/yj52hM
$ g++ -o main.exe --std=c++11 test_debugger.cpp && ./main.exe
test_debugger.cpp: In instantiation of ‘std::ostream& operator<<(std::ostream&, R (T::*)(Args ...)) [with T = test_debugger; R = int; Args = {}; std::ostream = std::basic_ostream<char>]’:
test_debugger.cpp:19:42: required from here
test_debugger.cpp:10:31: warning: converting from ‘int (test_debugger::*)()’ to ‘void*’ [-Wpmf-conversions]
return os << "funptr " << (void*)p;
^~~~~~~~
0. funptr 0x100401860
1. funptr 0x100401080
2. funptr 0x100401087
3. funptr 0x100401093
如何正确修复警告 warning: converting from ‘int (test_debugger::*)()’ to ‘void*’ [-Wpmf-conversions]
?
您的重载仅适用于函数指针,因为参数是函数指针。
它不适用于成员函数指针,因为成员函数指针不是函数指针,尽管这可能会造成混淆。您可以对成员函数指针使用类似的重载:
template<class C, class Ret, class... Args>
std::ostream& operator <<(std::ostream& os, Ret (C::*p)(Args...)) {
return os << "memfunptr " << "something...";
}
但是,成员函数指针不能转换为 void*
,因此您不能使用 void*
打印它们。您需要决定要在他们的案例中打印什么。如果您的目标只是获得一些可能与所指向的成员函数相关的输出,那么您可以执行以下操作:
unsigned char* internal_representation = reinterpret_cast<unsigned char*>(&p);
for(std::size_t i = 0; i < sizeof p; i++)
os << std::hex << (int)internal_representation[i];
P.S。在所有系统上也不允许将函数指针转换为 void*
。这是一个有条件支持的功能。它可能适用于至少使用动态链接的所有系统。
P.P.S。向标准 class 添加重载,其中所有参数都是标准 classes 或基本类型可能与未来的语言标准不兼容。
P.P.P.S。技术上不允许使用 main
地址。