Reputation: 914
I am trying to do the following: Obtain the address of a member function from a class that was locally defined within a function.
class ConnectionBase
{
};
template class<EventType, SinkType>
class ConnectionImpl : public ConnectionBase
{
public:
typedef void (SinkType::*EventCallback)(EventType const&);
};
template<class EventType>
class Source
{
template <class SinkType>
boost::shared_ptr<ConnectionBase> setupCallback(typename ConnectionImpl<EventType, SinkType>::EventCallback func, SinkType* sink)
{
// do the actual connecting.
}
};
class SomeClass
{
public:
void someFunction(int const& event){}
}
class SomeUnitTest
{
public:
void someTest()
{
class NestedClass
{
public:
void someFunction(int const& event){}
};
NestedClass nc;
//Try#1 - This does not work
setupCallback<int, NestedClass>(&NestedClass::someFunction, &nc);
//Try #2 - This also does not work
setupCallback<int, NestedClass>(&SomeUnitTest::someTest::NestedClass::someFunction, &nc);
//Try #3 - Following the GCC error output, I tried this
setupCallback<int, NestedClass>(&SomeUnitTest::someTest()::NestedClass::someFunction, &nc);
SomeClass sc;
//This works fine, as expected
setupCallback<int, SomeClass>(&SomeClass::someFunction, &sc);
}
};
Try #2 and #3 utterly confuse GCC, it has no idea what I am trying to do. Try #1 produces a more helpful error message saying no setupCallback exists that takes the form "setupCallback(void (SomeUnitTest::someTest()::NestedClass::SomeFunction::*), etc) Which is how try #3 was born.
I can't really find a lot of information about classes defined inside a function, does anyone know the correct syntax for this, and maybe have a resource that discusses this topic?
Ok, it appears this is settled, as both posters have pointed out, local classes have no linkage, it can't work. Now knowing this, I found this article that discusses this, for anyone else that runs into this problem and stumbles across this question: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=420
Edit:
Clarification of setupCallback(), working example with a more regular class
Edit #2:
Updated wording to change "nested" to "local". Added more detail for setupCallback.
Edit #3: Added links to furhter information. Thanks everyone.
Upvotes: 3
Views: 2374
Reputation: 99092
I don't know about the syntax problem, the usual access rules should apply - but there is another problem here if that would work as these member functions have no linkage.
To accept local types at all, setupCallback()
would have to be a template function - but template type arguments with no linkage are not allowed.
§3.5/8 says:
Names not covered by these rules have no linkage. Moreover, except as noted, a name declared in a local scope (3.3.2) has no linkage.
Members of local classes are not covered there. §9.3/3 clarifies that:
Member functions of a local class (9.8) have no linkage.
Long story cut short: don't use member functions of a local class as callbacks, use a non-local class instead.
Upvotes: 4
Reputation: 320747
You fist variant is the correct one as long as the specific matter of taking the address is considered. There are no restrictions on taking the address of member functions of local classes. The proper syntax is the usual
&NestedClass::someFunction
ans that's it. You can try saving it in an intermediate pointer in your code
void (NestedClass::*ptr)() = &NestedClass::someFunction;
and I'm sure your compiler will accept it.
However, the problem I suspect exists in your code has absolutely nothing to do with the proper way of taking the address of a member function. It is rather about the way the first parameter of setupCallback
is declared. Since you say it works with &SomeClass::someFunction
as the first argument, I'd expect setupCallback
to be declared as
void setupCallback(void (SomeClass::*cb)(), SomeClass *p); // one possibility
i.e. it is hardcoded to expect a pointer to a member of SomeClass
specifically. You cannot supply a pointer to a member of NestedClass
instead. NestedClass
is completely unrelated to SomeClass
and pointers to members of NestedClass
are completely incompatible with pointers to members of SomeClass
. This is why it won't compile.
Unless there's something you are not showing us (like setupCallback
being a function template maybe? Or overloaded for different parameter types?), what you are trying to do is simply impossible to achieve regardless of how you take the member address, as long as NestedClass
remains unrelated to SomeClass
. Function setupCallback
is designed to work with SomeClass
and SomeClass
only.
Provide more information about setupCallback
. How is it declared?
Note that if the setupCallback
is declared as a function template parametrized by class type, as in
template <class T> void setupCallback(void (T::*cb)(), T* p);
then you won't be able to use the local class NestedClass
as template argument for parameter T
. In this case the fact that your NestedClass
has no linkage does indeed come into play. But, again, it has nothing to do with taking the member address, but rather caused by the fact that classes with no linkage cannot be used as template arguments in C++.
Upvotes: 4