I'm asking for a template trick to detect if a class has a specific member function of a given signature.
The problem is similar to the one cited here http://www.gotw.ca/gotw/071.htm but not the same: in the item of Sutter's book he answered to the question that a class C MUST PROVIDE a member function with a particular signature, else the program won't compile. In my problem I need to do something if a class has that function, else do "something else".
A similar problem was faced by boost::serialization but I don't like the solution they adopted: a template function that invokes by default a free function (that you have to define) with a particular signature unless you define a particular member function (in their case "serialize" that takes 2 parameters of a given type) with a particular signature, else a compile error will happens. That is to implement both intrusive and non-intrusive serialization.
I don't like that solution for two reasons:
- To be non intrusive you must override the global "serialize" function that is in boost::serialization namespace, so you have IN YOUR CLIENT CODE to open namespace boost and namespace serialization!
- The stack to resolve that mess was 10 to 12 function invocations.
I need to define a custom behavior for classes that has not that member function, and my entities are inside different namespaces (and I don't want to override a global function defined in one namespace while I'm in another one)
Can you give me a hint to solve this puzzle?
To be non-intrusive, you can also put
serialize
in the namespace of the class being serialised, or of the archive class, thanks to Koenig lookup. See Namespaces for Free Function Overrides for more details. :-)Opening up any given namespace to implement a free function is Simply Wrong. (e.g., you're not supposed to open up namespace
std
to implementswap
for your own types, but should use Koenig lookup instead.)Here's a possible implementation relying on C++11 features. It correctly detects the function even if it's inherited (unlike the solution in the accepted answer, as Mike Kinghan observes in his answer).
The function this snippet tests for is called
serialize
:Usage:
Here are some usage snippets: *The guts for all this are farther down
Check for member
x
in a given class. Could be var, func, class, union, or enum:Check for member function
void x()
:Check for member variable
x
:Check for member class
x
:Check for member union
x
:Check for member enum
x
:Check for any member function
x
regardless of signature:OR
Details and core:
Macros (El Diablo!):
CREATE_MEMBER_CHECK:
CREATE_MEMBER_VAR_CHECK:
CREATE_MEMBER_FUNC_SIG_CHECK:
CREATE_MEMBER_CLASS_CHECK:
CREATE_MEMBER_UNION_CHECK:
CREATE_MEMBER_ENUM_CHECK:
CREATE_MEMBER_FUNC_CHECK:
CREATE_MEMBER_CHECKS:
I'm not sure if I understand you correctly, but you may exploit SFINAE to detect function presence at compile-time. Example from my code (tests if class has member function size_t used_memory() const).
I believe the answer you are looking for is here.
http://www.martinecker.com/wiki/index.php?title=Detecting_the_Existence_of_Operators_at_Compile-Time
and a slightly more filled out example here
http://pastie.org/298994
I use the technique to detect the presence of a supporting ostream operator << on the class in question and then generate a different bit of code depending.
I didn't believe it was possible before finding the linked solution but it is a very neat trick. Spend the time understanding the code and it is very worth the while.
Brad
To accomplish this we'll need to use:
type_traits
header, we'll want to return atrue_type
orfalse_type
from our overloadstrue_type
overload expecting anint
and thefalse_type
overload expecting Variadic Parameters to exploit: "The lowest priority of the ellipsis conversion in overload resolution"true_type
function we will usedeclval
anddecltype
allowing us to detect the function independent of return type differences or overloads between methodsYou can see a live example of this here. But I'll also explain it below:
I want to check for the existence of a function named
test
which takes a type convertible fromint
, then I'd need to declare these two functions:decltype(hasTest<a>(0))::value
istrue
(Note there is no need to create special functionality to deal with thevoid a::test()
overload, thevoid a::test(int)
is accepted)decltype(hasTest<b>(0))::value
istrue
(Becauseint
is convertable todouble
int b::test(double)
is accepted, independent of return type)decltype(hasTest<c>(0))::value
isfalse
(c
does not have a method namedtest
that accepts a type convertible fromint
therefor this is not accepted)This solution has 2 drawbacks:
test()
method?So it's important that these functions be declared in a details namespace, or ideally if they are only to be used with a class, they should be declared privately by that class. To that end I've written a macro to help you abstract this information:
You could use this like:
Subsequently calling
details::test_int<a>::value
ordetails::test_void<a>::value
would yieldtrue
orfalse
for the purposes of inline code or meta-programming.