-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot print function pointer #68
Comments
Just casting it to a function pointer also does not work: #include "tinyformat.h"
int main(int argc, char const *argv[])
{
typedef int (*Function)( int argc, char const *argv[] );
std::cerr << tfm::format( "var2 %s", (Function) main ) << std::endl;
return 0;
} Results:
|
The root cause here is the ambiguity between converting a function pointer to a #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 There's already some workarounds for behaving more like One option may be replacing the Another option might be to have a special case for pointers with |
I prefer to fix the If the How this |
I'm not sure this will work out cleanly. Generally the rule for The general point here is that it's part of the public interface that
Unfortunately all those solutions rely on |
It would be very nice if we could patch/fix the buggy
If these condition are not meet, then we could just do what we usually do, i.e., no conversion before passing it to the
I found a decltype implementation for C++ 98:
This is a minimal working code without requiring the boost library: #include <iostream>
#include <typeinfo>
template<int N> struct sizer { char value[N]; };
sizer<1> encode(char);
sizer<2> encode(unsigned char);
sizer<3> encode(signed char);
sizer<4> encode(bool);
sizer<5> encode(float);
// ...
template<int N> struct decode {};
template<> struct decode<1> { typedef char type; };
template<> struct decode<2> { typedef unsigned char type; };
template<> struct decode<3> { typedef signed char type; };
template<> struct decode<4> { typedef bool type; };
template<> struct decode<5> { typedef float type; };
// ...
#define TYPEOF(expr) decode<sizeof(encode(expr))>::type
int main() {
int a; float b;
TYPEOF(a+b) c = a+b;
std::cout << typeid(c).name() << std::endl;
} Compiling it:
Should it be enough? It's only downside is that all supported types need to be enumerated before hand. |
@c42f, I found a solution for the iostream overloading problem: #include<iostream>
template<class Ret, class... Args>
std::ostream& operator <<(std::ostream& os, Ret(*p)(Args...) ) {
return os << "funptr " << (void*)p;
}
template <typename T, typename R, typename ...Args>
std::ostream& operator <<(std::ostream& os, R (T::*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. funptr 0x100401860
// 1. funptr 0x100401080
// 2. funptr 0x100401087
// 3. funptr 0x100401093
We could attach this conversion to some inner layer instead of globally defining it for all |
template<class Ret, class... Args>
std::ostream& operator <<(std::ostream& os, Ret(*p)(Args...) ) {
return os << "funptr " << (void*)p;
} Plausibly we could attach some conversion like this as a new version of |
It can be written easily in C++<11, it just translates to N+1 function definitions each taking function pointers to functions with 0, 1, ... N arguments. Also, 2*N if you also need to handle |
Using a trick with the Here's a very cut down template<typename> struct is_pointer { static const bool value = false; };
template<typename T> struct is_pointer<T*> { static const bool value = true; };
template<typename T> struct is_pointer<const T*> { static const bool value = true; };
template<typename T> struct is_pointer<volatile T*> { static const bool value = true; };
template<typename T> struct is_pointer<const volatile T*> { static const bool value = true; }; |
At a first glance it should work, or at least I can't see a reason why it wouldn't. For maximum compatibility we tag dispatch on the trait and that way we only have to write 2 implementations (so 3 functions counting the dispatcher). I don't know why didn't I think of that before. |
I just figure out the C++ equivalent for it with C++ 98. This cannot be done with the current macros because the function pointer signature cannot be something like:
It has to be something like:
Minimal working example: https://godbolt.org/z/PJ66sR #include<iostream>
template<typename Return>
std::ostream& operator <<(std::ostream& os, Return(*pointer)() ) {
return os << (void*) pointer;
}
template<typename Return, typename T0>
std::ostream& operator <<(std::ostream& os, Return(*pointer)( T0 t0 ) ) {
return os << (void*) pointer;
}
template<typename Return, typename T0, typename T1>
std::ostream& operator <<(std::ostream& os, Return(*pointer)( T0 t0, T1 t1 ) ) {
return os << (void*) pointer;
}
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}
int main() {
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:
// 1. funptr 0x100401080
// 2. funptr 0x100401087
// 3. funptr 0x100401093
|
@evandrocoan I don't think that's the way to go. It relies on enumerating an unbounded list of cases and is a lot of machinery to fix what is — in my view — a small wart. I think an |
For an C++ 98 is_pointer version I found these alternatives: https://stackoverflow.com/questions/3177686/how-to-implement-is-pointer Which one you like most? template <typename T>
struct is_pointer
{ static const bool value = false; };
template <typename T>
struct is_pointer<T*>
{ static const bool value = true; }; But I am not sure if it is the best as the fist answer is quite big: template <typename T>
struct remove_const
{
typedef T type;
};
template <typename T>
struct remove_const<const T>
{
typedef T type;
};
... |
Results in:
If I remove the
&main
and use onlymain
, it does not compile:Example using a volatile variable:
Results in the same
The text was updated successfully, but these errors were encountered: