Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use boost::enable_if on a member function?

I'm writing a template class, and I want to allow an additional method to exist only for a certain template type. Currently the method exists for all template types, but causes a compilation error for all other types.

Complicating this is that it's an overloaded operator(). Not sure if what I want to do is actually possible here.

Here's what I have now:

template<typename T, typename BASE>
class MyClass  : public BASE
{
public:

    typename T& operator() (const Utility1<BASE>& foo);
    typename T const& operator() (const Utility2<BASE>& foo) const;
};

I want the T& version always available, but the T const& version only available if Utility2<BASE> is valid. Right now, both methods exist, but attempting to use the const version gives a weird compilation error if Utility2<BASE> is invalid. I'd rather have a sensible error, or even a "no such member function" error.

Is this possible?

EDIT: After reading through the boost docs, here's what I've come up with, and it seems to work:

template<typename T, typename BASE>
class MyClass  : public BASE
{
public:

    typename T& operator() (const Utility1<BASE>& foo);

    template<typename U>
    typename boost::enable_if<boost::is_same<Utility2<BASE>, U>, T>::type const &
    operator() (const U& foo) const;
};

So that method doesn't exist unless someone tries to use it with Utility2, and they can only create a Utility2 if it's valid for that BASE type. But when it's not valid for that BASE type, MyClass will not waste time creating the accessor method.

like image 259
Tim Avatar asked Feb 02 '11 22:02

Tim


1 Answers

Yes, this is possible, but not with the class template parameter directly. boost::enable_if can only be used with a template parameter on the method itself. So, with a little typedef usage:

template<typename T, typename BASE>
class MyClass  : public BASE
{
public:
  typedef Utility2<BASE> util;

  typename T& operator() (const Utility1<BASE>& foo);

  template<typename U>
  typename boost::enable_if<boost::is_same<util, U>, T>::type const &
  operator() (const U& foo) const;
};

This works, because Utility2 can only be created from a certain BASE type. So if the BASE type is something else, the const version of operator() won't exist.

So, it's a very minor thing. It doesn't gain me much. But it was neat to do.

like image 171
Tim Avatar answered Oct 12 '22 07:10

Tim