I'm having a hard time understanding why the following snippet compiles. I have a template class ptr_to_member<T>
which stores a pointer to a member function of T
. I am then creating a new class my_class
which has a ptr_to_member<my_class>
. I expected the latter to cause a compilation error given that my_class
is still being defined. Any help is appreciated. Thank you.
#include <iostream>
// this class simply stores a pointer to a member function of T
template <class T>
struct ptr_to_member {
using ptr_type = void (T::*)();
ptr_type m_ptr;
ptr_to_member()
: m_ptr(&T::f){}
auto get_ptr() const {
return m_ptr;
}
};
// my_class has a ptr_to_member<my_class>
class my_class {
ptr_to_member<my_class> m_ptr_to_member; // why does this compile?
public:
void g() {
auto ptr = m_ptr_to_member.get_ptr();
(this->*ptr)();
}
void f() {
std::cout << "f" << std::endl;
}
};
int main() {
my_class x;
x.g();
}
While defining a class, that class can be used as if it were forward declared. Since ptr_to_member
only uses pointers to T
until you instantiate one of it's methods, it doesn't complain. Try adding a member T
rather than a pointer and you will see that it fails. The intuitive way of seeing it is that you don't need to know what T
is to use a pointer of T
, only that T
is a type. Pointers behave the same way regardless of what they point to until you dereference them.
template <class T>
struct ptr_to_member {
using ptr_type = void (T::*)();
ptr_type m_ptr;
ptr_to_member()
: m_ptr(&T::f) {}
auto get_ptr() const {
return m_ptr;
}
T member; // Add this and see that it fails to compile
};
See this answer for more information on when you can and can't use forward declared types.