Consider the following code:
template <class>
struct test: std::integral_constant<int, 0> {};
template<class R, class C, class... Args>
struct test<R(C::*)(Args...)>: std::integral_constant<int, 1> {};
template<class R, class C, class... Args>
struct test<R(*C::*)(Args...)>: std::integral_constant<int, 2> {};
template<class R, class C, class... Args>
struct test<R(**C::*)(Args...)>: std::integral_constant<int, 3> {};
template<class R, class C, class... Args>
struct test<R(C::**)(Args...)>: std::integral_constant<int, 4> {};
template<class R, class C, class... Args>
struct test<R(C::***)(Args...)>: std::integral_constant<int, 5> {};
I have absolutely no idea of what (*C::*)
, (**C::*)
, (C::**)
and (C::***)
mean. I would like an example of a test<decltype(f)>
whose value
would be equal to 2
, 3
, 4
and 5
. Plus, in that case, how is the syntax for f
that would call the member function?
A pointer to a function points to the address of the executable code of the function. You can use pointers to call functions and to pass functions as arguments to other functions.
In C, like normal data pointers (int *, char *, etc), we can have pointers to functions. Following is a simple example that shows declaration and function call using function pointer. #include <stdio.h> // A normal function with an int parameter. // and void return type.
The pointer to member operators . * and ->* are used to bind a pointer to a member of a specific class object. Because the precedence of () (function call operator) is higher than . * and ->* , you must use parentheses to call the function pointed to by ptf .
Function pointers in C can be used to create function calls to which they point. This allows programmers to pass them to functions as arguments. Such functions passed as an argument to other functions are also called callback functions.
Consider this example:
struct s {
void test1();
void(*test2)();
void(**test3)();
};
int main() {
static_assert(test<decltype(&s::test1)>::value == 1);
static_assert(test<decltype(&s::test2)>::value == 2);
static_assert(test<decltype(&s::test3)>::value == 3);
auto test4 = &s::test1;
static_assert(test<decltype(&test4)>::value == 4);
auto test5 = &test4;
static_assert(test<decltype(&test5)>::value == 5);
}
Here are the types:
R(C::*)(Args...)
- A pointer to a member function.R(*C::*)(Args...)
- A pointer to a data member that is a function pointer.R(**C::*)(Args...)
- A pointer to a data member that is a pointer to a function pointer.R(C::**)(Args...)
- A pointer to a pointer to a member function.R(C::***)(Args...)
- A pointer to a pointer to a pointer to a member function.
To call these, consider a slightly modified example:
struct s {
void test1() {std::cout << "test1\n";}
void(*test2)() = [] {std::cout << "test2\n";};
void(*test3Helper)() = [] {std::cout << "test3\n";};
void(**test3)() = &test3Helper;
void test4() {std::cout << "test4\n";}
void test5() {std::cout << "test5\n";}
};
int main() {
s obj;
auto test4 = &s::test4;
auto test5Helper = &s::test5;
auto test5 = &test5Helper;
(obj.*(&s::test1))();
(*(obj.*(&s::test2)))(); // note that the dereference is unnecessary
(**(obj.*(&s::test3)))(); // note that the second dereference is unnecessary
(obj.**(&test4))();
(obj.***(&test5))();
}
Note that in each case, if you have a variable with the value of the appropriate &[s::]testN
, you can replace (&[s::]testN)
with that variable. Note also that for test2 and test3, I dereferenced until getting the function back rather than the function pointer for illustration purposes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With