boost enable_if and has_xxx mecanic ?

Started by
4 comments, last by pitoneux 13 years, 10 months ago
Hi there,


I need help here to understand how enable_if could allow me to call a specialized method when a certain member exists in template class parameter.

I'm basically trying to come up with a portable __if_exists macro found only in Microsoft land.


I have this in header file:

template<class Primitive, class Contact, class ContactManager, int MAX_LEVELS>class A {	    BOOST_MPL_HAS_XXX_TRAIT_DEF(getFirstContact);    [...]     void foo(Primitive* p);    void foo(Primitive* p, typename boost::enable_if<has_getFirstContact<Primitive> >::type *dummy=0);}



in the cpp file:

template<class Primitive, class Contact, class ContactManager, int MAX_LEVELS>voidA<Primitive, Contact, ContactManager, MAX_LEVELS>::foo(Primitive* p, typename boost::enable_if<has_getFirstContact<Primitive> >::type* dummy = 0){ ... }template<class Primitive, class Contact, class ContactManager, int MAX_LEVELS>voidA<Primitive, Contact, ContactManager, MAX_LEVELS>::foo(Primitive* p){ ... }


errors I'm getting in vc08:

[line in header file] error C2039: 'type' : is not a member of 'boost::enable_if<Cond>'

I'm probably missing a lot here...


Advertisement
foo isn't templated, so it isn't subject to SFINAE, which is required to use enable_if. It belongs to a templated class, but that doesn't help. We can abuse specialization:

#include <boost/mpl/has_xxx.hpp>#include <iostream>template<class Primitive, class Contact, class ContactManager, int MAX_LEVELS>class A {	BOOST_MPL_HAS_XXX_TRAIT_DEF(getFirstContact);	template < bool B > void foo_impl( Primitive* p ) { std::cout << "Has getFirstContact\n"; }	template <> void foo_impl<false>( Primitive* p ) { std::cout << "Does not have getFirstContact\n"; }public:	void foo(Primitive* p) { foo_impl<has_getFirstContact<Primitive>::value>(p); }};struct No {};struct Yes { typedef void getFirstContact; };int main() {	A<No ,void,void,0> a; a.foo(0);	A<Yes,void,void,0> b; b.foo(0);}
okay... (BIG thanks for looking into this!) but here's what gcc tells me when I compile this:

GNU C++ version 4.2.1 (Apple Inc. build 5664) (i686-apple-darwin10)
compiled by GNU C version 4.2.1 (Apple Inc. build 5664).
GGC heuristics: --param ggc-min-expand=150 --param ggc-min-heapsize=131072
Compiler executable checksum: b2d9fc2676bcbc4fe5c6f07f902dbb00
/Users/ericlebel/pp.cpp:9: error: explicit specialization in non-namespace scope ‘class A<Primitive, Contact, ContactManager, MAX_LEVELS>’


so I guess it's no no with gcc... (specialization on function) ?
Long story short, MaulingMonkey's example is actually non-standard C++ that Visual C++ doesn't mind, but GCC doesn't like, and as a general rule as far as I'm aware an explicit specialization of a templated member must be a member of an explicit specialization. Bit of a nasty problem (at least trying to figure it out this late it is), but try something like this:

BOOST_MPL_HAS_XXX_TRAIT_DEF(getFirstContact);template<class Primitive, bool HasGetFirst>class fooImpl{    void foo(Primitive* p); // Version for when it's false};template<class Primitive>class fooImpl<Primitive, true>{    void foo(Primitive* p); // Version for when it's true};template<class Primitive, class Contact, class ContactManager, int MAX_LEVELS>class A : public fooImpl<Primitive, has_getFirstContact<Primitive>::value> {};


I'm sure there are better ways to work around the problem, but they'd probably depend on knowing more about the structure of your classes and what they're doing with each other.

EDIT: This is the kind of thing that good ol' fashioned polymorphism is best suited for dealing with.
Other alternatives include making foo_impl a proper free function, explicitly passing in a pointer to the class and making it a friend of the class as necessary.
thank you guys. I ended up using your suggestion Shinkage.


since I'm porting this code to the Mac, I have a lot of code to write in order to replace the __if_exists call...

(would it be thinkable to write a macro to replace __if_exists and make it portable ?)

This topic is closed to new replies.

Advertisement