# SFINAE

This topic is 2919 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I have something that looks like:

[source lang="cpp"]
template <typename T>
struct Traits
{
typedef BOOST_TYPEOF(&T::operator()) MemOpPtr;
// ... boost::function_types and mpl magic ...
};

template <typename O, typename I>
struct Traits<O (*)(I)>
{ /* ... */ };

template <typename T> void func(const T& o)
{ /* uses Traits<T> */ }

// overload B - binds a boost::function holding T::operator() to p
template <typename T> void func(const boost::shared_ptr<T>& p)
{ /* uses Traits<T> */ }[/source]

How can I have overload B be used when A's Traits substitution fails? I can just rename the second overload, but would prefer to keep the same syntax if possible. At the moment, I'll get errors telling me that operator() isn't a member of boost::shared_ptr. BOOST_TYPEOF (alone) doesn't give SFINAE, but I think something like enable_if< is_defined<T::operator()> > on the default Traits would suffice?

Thanks.

##### Share on other sites
Off the top of my head, so the concept should work even if the strict syntax doesn't ;-)

template <typename T> void func(const T& o, const T::MemOpPtr& = T::MemOpPtr()) { // ... }

Substitution will fail if T does not provide the MemOpPtr typedef, and fall back on the second overload.

I think.

You might have to do some trickery with fake variadic functions to get all compilers to do this cleanly, I can't remember offhand.

##### Share on other sites
Hm, but I've already got something similar, albeit in the return type. Sorry, I'll post my actual code:

[source lang="cpp"]namespace ppl
{
template <typename T>
struct StageTraits
{
typedef BOOST_TYPEOF(&T::operator()) MemOpPtr;

typedef typename boost::function_types::result_type<MemOpPtr>::type O;
typedef typename boost::mpl::at_c<boost::function_types::parameter_types<MemOpPtr>, 1>::type I;

typedef boost::function<O (I)> F;
};

template <typename O, typename I>
struct StageTraits< boost::function<O (I)> >
{ typedef boost::function<O (I)> F; };

template <typename O, typename I>
struct StageTraits<O (*)(I)>
{ typedef boost::function<O (I)> F; };

template <typename T>
detail::List<typename StageTraits<T>::F, detail::Empty> stage(const T& f)
{ return detail::List<typename StageTraits<T>::F, detail::Empty>(typename StageTraits<T>::F(f)); }

template <typename T>
detail::List<typename StageTraits<T>::F, detail::Empty> stage(const boost::shared_ptr<T>& f_obj)
{
typename StageTraits<T>::F f(boost::bind(&T::operator(), f_obj, _1));
return detail::List<typename StageTraits<T>::F, detail::Empty>(f);
}
}[/source]

Example usage:
[source lang="cpp"]int inc(int x) { return x+1; }
int mul(int a, int b) { return a*b; }

{
int d;

: d(d)
{}

int operator()(int x) { return x+d; }
};

void test_pipeline()
{
ppl::stage(&inc);
ppl::stage(boost::function<int (int)>(boost::bind(&mul, 2, _1)));

}[/source]
Error: ‘operator()’ is not a member of ‘boost::shared_ptr<Add>’ [pointing at every line in the first StageTraits]

What sort of trickery might be needed? Googling only turned up stuff about variadic templates.

##### Share on other sites
Working with limited time, so apologies if I only get you halfway to a solution :-)

SFINAE only applies in limited situations; you won't trigger it by any arbitrary compilation failure, but rather only specific type-substitution failures. To make it work, you need some helper typedefs and some other evil.

This page is my personal go-to reference for how to get back into the mindset of C++ template metaprogramming (I'll admit to being rusty at this exact moment) and it might offer some insight into what needs to be done to make your idea work.

My hunch at the moment is that what you need is to make your first StageTraits be a special case, i.e. it needs to have some enable-if magic to prevent it from being instantiated at all for a T that isn't a functor. The easy, simple way to do this is to have your functors expose a typedef that only they hold, which is a form of tagging (I use this a lot). There might be a magic solution that can detect arbitrary functors and distinguish them from other things that look like function calls, but that's voodoo beyond my depth I'm afraid :-)

##### Share on other sites
No problem, that gives me a starting point. Thanks very much!

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 13
• 9
• 11
• 15
• 21