Search code examples
c++templatesc++11function-templates

In C++ 11, how do I specialize a function template that takes a function object based on return type?


I have a wrapper function in C++ 11, designed to be used with lambdas, like so:

template<typename Func>
int WrapExceptions(Func&& f)
{
  try
  {
    return f();
  }
  catch(std::exception)
  {
    return -1;
  }
}

And I can call it like so:

int rc = WrapExceptions([&]{
  DoSomething();
  return 0;
});
assert(rc == 0);

And life is OK. What I want to do, though, is overload or specialize the wrapper function such that when the inner function returns void, the outer function returns a default value of 0, e.g.:

int rc = WrapExceptions([&]{
  DoSomething();
});
assert(rc == 0);

Can I actually do this in C++ 11? I cannot for the life of me think of how.


Solution

  • You may use SFINAE:

    • with std::result_of

      template<typename Func>
      typename std::enable_if<
          std::is_convertible<typename std::result_of<Func()>::type, int>::value,
          int
          >::type
      WrapExceptions(Func&& f)
      {
        try { return f(); }
        catch(std::exception) { return -1; }
      }
      
      template<typename Func>
      typename std::enable_if<
          std::is_same<void, typename std::result_of<Func()>::type>::value,
          int
          >::type
      WrapExceptions(Func&& f)
      {
        try { f(); return 0; /* default value */ }
        catch(std::exception) { return -1; }
      }
      
    • with decltype:

      template<typename Func>
      auto
      WrapExceptions(Func&& f)
      -> typename std::enable_if<
          std::is_convertible<decltype(f()), int>::value,
          int
          >::type
      {
        try { return f(); }
        catch(std::exception) { return -1; }
      }
      
      template<typename Func>
      auto
      WrapExceptions(Func&& f)
      -> typename std::enable_if<
          std::is_same<void, decltype(f())>::value,
          int
          >::type
      {
        try { f(); return 0; }
        catch(std::exception) { return -1; }
      }