Search code examples
c++templatesboostenable-if

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.


Solution

  • 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.