It fails to compile because ip isn’t a compile-time constant.
All template arguments must be compile-time constants.
In this case, to trigger the correct template you can static_castnullptr,
as I will demonstrate in a moment…
This is either a trick question or the author doesn’t know what static means.
(I’m going to assume it’s a trick question designed to test your knowledge,
or, since I’m the one providing the answer, my knowledge. :P)
There’s no such thing as a pointer to a static member function because a static member function behaves like a normal function,
so to point to a static member function you’d use a normal function pointer.
Similarly a pointer to a static class member would just be a normal pointer.
Pointers to non-static member functions are however separate entities with special syntax, as I will now demonstrate:
#include <iostream>
template<int i>
void test_int()
{
std::cout << i << '\n';
}
template<int * pointer>
void test_int_pointer()
{
std::cout << pointer << '\n';
}
class some_class
{
public:
int member_function()
{
return 0;
}
static int static_member_function()
{
return 0;
}
static int static_member_variable;
};
int some_class::static_member_variable = 0;
template<typename Type, int (Type::* member)()>
void test_member_function_pointer()
{
std::cout << member << '\n';
}
template<int (* function)()>
void test_function_pointer()
{
std::cout << function << '\n';
}
int main()
{
test_int<100>();
test_int_pointer<static_cast<int*>(nullptr)>();
test_member_function_pointer<some_class, &some_class::member_function>();
test_function_pointer<some_class::static_member_function>();
test_int_pointer<&some_class::static_member_variable>();
std::cin.get();
}
The reason a pointer to a member function is different from a normal function pointer is because of the way the this pointer is implemented.
When you write object.function(), it’s actually implemented like function(object) as if function were defined as void function(Object * this).
C++'s is designed to keep the this parameter implicit, and to make it difficult to provide an invalid object for this.
The kind of function call used on member functions is sometimes called a ‘thiscall’.
Hi Pharap:
if non-type parameters must be a complie-time constant,
Why " test_member_function_pointer<some_class, some_class::member_function>();" can be complied;
I think a normal member function needs ‘this’ - a runtime pointer.
Because the address of any function is a compile time constant.
(Similarly the address of any variable with ‘static storage duration’ (chinese version) is a compile time constant.)
A member function is still a compile time constant because the function itself doesn’t change.
The implicit this parameter is given to the function like an argument.
E.g. consider this class:
class A
{
public:
int value;
int get_value() const
{
return this->value;
}
};
Assuming A a {};, int b = a.get_value();,
the compiler would translate the code into something like this:
class A
{
public:
int value;
};
int A_get_value(const A * this)
{
return this->value;
}
The function itself doesn’t change.
The this pointer given to the function changes.
As you said:
int member_function(){return 0;} has a implicited parameter - ‘this’,
looks like int member_function(some_class* this){return 0;}
and ‘this’ is a runtime object pointer, so if I want to using this normal member function pointer, firstly must create a object.
but as your code
test_member_function_pointer<some_class, &some_class::member_function>();
seem not create a object of some_class ?!
Im full of chao:~
And why the template test_member_function_pointer needs typename Type parameter, template test_function_pointer not need it?
If you want to call the function, yes.
But you don’t have to call a function to know where it is.
Getting the address of a function does not ‘use’ the function.
A strange analogy: I can tell you where the teapot is without pouring tea.
Member function pointers use different syntax because of the special this parameter.
The function needs to know what type the hidden this parameter is.
void (T::*)() specifies that the type of this is T *.
It’s a bit like how void (*)(int) specifies that the first argument is int.
Also, the way non-member function pointers and member function pointers are called is different…
#include <iostream>
template<int * pointer>
void test_int_pointer()
{
std::cout << pointer << '\n';
}
class some_class
{
public:
int member_function()
{
return 999;
}
};
template<typename Type, int (Type::* member)()>
void test_member_function_pointer()
{
//there is just tell complier the detail type of this pointer(Type:: tells the complier the type of this), not using it. so it can be compile.
//there output the pointer's size - 1 storge unit. (not using the member function)
std::cout << member << '\n';
}
int main()
{
test_member_function_pointer<some_class, &some_class::member_function>();
test_member_function_pointer<some_class, some_class::member_function>();
//why add '&' or nothing before 'some_class::member_function' has the same result ???????
return 0;
}
Ah, I know what the problem is.
Apparently std::cout can’t print member function pointers.
For some reason member is being implicitly converted to bool.
(If you put std::cout << std::boolalpha; at the start of main, you get true instead of 1.)