Jump to content
  • Advertisement
Sign in to follow this  
TheUnbeliever

SFINAE

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

If you intended to correct an error in the post then please contact us.

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)>
{ /* ... */ };

// overload A
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 this post


Link to post
Share on other sites
Advertisement
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 this post


Link to post
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; }

struct Add
{
int d;

Add(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)));

boost::shared_ptr<Add> add(new Add(1));
ppl::stage(add);
}[/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 this post


Link to post
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 this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!