5

I have a function foo() that is being provided in a library context. The library defines a handful of overloads for this function, like:

char foo(float x, int y);
short foo(double x, char y);

(I made the above argument/result types up. The takeaway is that there isn't a generic relationship between the argument types and the overload's corresponding return type.)

The idea is that the library user can add overloads for foo() for their own user-defined types as needed. Function overloading accomplishes this very easily.

I would like to make the foo() family of functions usable in a Boost.Proto expression. In order to do so, I think I would need to wrap the above in a function object with a template call operator:

struct foo_wrap
{
    template <typename A1, typename A2>
    result_type operator()(A1 a1, A2 a2) { return foo(a1, a2); }
};

The problem comes with how to define result_type. I realize this would be easy with C++11 and decltype() and trailing function return types, but I'm looking for a C++03 solution. Therefore, foo_wrap needs to be a TR1-style function object. I need to find a way to define result_type as a compile-time function of the argument types A1 and A2. This is needed not only for the return type of operator(), but also for the TR1 result_of protocol to work as well. In short:

  • Is there a metaprogramming technique that, given a function name and a set of argument types, will yield the function's corresponding return type?
  • Alternatively, is there another technique that I can use to wrap multiple overloads of a function with a generic function object?
Jason R
  • 11,159
  • 6
  • 50
  • 81
  • How portable do you have to be in terms of support for various compilers? – cdhowie Dec 19 '14 at 19:35
  • I'm looking to support any reasonably C++03-compatible compiler. Probably a minimum of gcc 4.1 or so. I'm not particularly concerned with MSVC, although it would be nice if it worked there too. – Jason R Dec 19 '14 at 19:37
  • If g++ is your primary target you *may* be able to use its proprietary `typeof()` feature here. – cdhowie Dec 19 '14 at 19:38
  • Thanks, that seems to be worth a look. It looks like an almost-equivalent to `decltype`, so it might get the job done. Looks like it works on clang too, so that's nice. It would be good to have a more standard technique, but I suspect there may not be one. – Jason R Dec 19 '14 at 19:42
  • *"Is there a metaprogramming technique that, given a function name and a set of argument types, will yield the function's corresponding return type?"* You cannot pass an overload set around in C++ (neither as a function argument, nor as a template argument). `boost::result_of` has a similar problem for class types with several `operator()` overloads, and they have no automatic solution in C++03. A manual solution is of course to define a (manual) mapping between the argument types and the return type. – dyp Dec 19 '14 at 19:54
  • @dyp: Thanks for your input. Perhaps I can just define a macro to aid the user in creating additional overloads. Given a set of argument types and a result type, the macro could emit a specialization for `foo_wrap::result<>` (as needed for the TR1 protocol) in addition to the function signature. Something like: `DECL_FUNC_OVERLOAD(foo, char, float, int) { /* implementation here */ }`. – Jason R Dec 19 '14 at 20:02

1 Answers1

4

You may feed manually a traits for that:

template <typename A1, typename A2>
struct foo_wrap_result;

with

struct foo_wrap
{
    template <typename A1, typename A2>
    typename foo_wrap_result<A1, A2>::type
    operator()(A1 a1, A2 a2) const { return foo(a1, a2); }
};

And specialization of the traits:

template <>
struct foo_wrap_result<float, int> { typedef char type; };

template <>
struct foo_wrap_result<double, char> { typedef short type; };
Jarod42
  • 203,559
  • 14
  • 181
  • 302