0

I want to declare a method - variadic - where its signature comes from an "old-style" function signature as template parameter.

You can declare, say, a std::function using a function signature, e.g.,

std::function<int(float,float)> f;

Now I'd like to have a template which takes a function signature like that and declares a method somehow:

template <typename F>
struct Foo {
   [F's-return-type] Method(F's-Arg-pack]...) { ... }
};

So if you instantiate it as follows you get a method as follows:

   Foo<int(float,float)> foo;
   int x = foo.Method(1.0f, 2.0f);

Or maybe there's a different way to do this?

davidbak
  • 5,775
  • 3
  • 34
  • 50
  • related/dupe: https://stackoverflow.com/questions/9065081/how-do-i-get-the-argument-types-of-a-function-pointer-in-a-variadic-template-cla – NathanOliver Mar 18 '21 at 20:24

3 Answers3

7

You can disassemble F using a pretty straightforward partial specialization:

template <class F>
struct Foo;

template <class Ret, class... Params>
struct Foo<Ret(Params...)> {
    Ret Method(Params...) { /* ... */ }
};

See it live on Coliru

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • Didn't even occur to me to partially-specialize in that way. Partial-specialization is pretty flexible! (Will choose an answer to green-check later ...) – davidbak Mar 18 '21 at 20:56
1

But of course! Result type is easy, this is simply std::function::result_type. Extracting argument type is less straightforward, and requires partial class specialization (at least, in my solution):

template<class F> struct Foo;
template<class R, class... Args>
struct Foo<std::function<R(Args...)>
{
   R Method(Args... args) { ... }
};
SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Didn't even occur to me to partially-specialize in that way. Partial-specialization is pretty flexible! (Will choose an answer to green-check later ...) – davidbak Mar 18 '21 at 20:55
0

You need partial specializations, one for each kind of functions. hopefully for regular functions (so not the abominable functions), there are less:

template <class Sig>
struct Foo;

template <typename Ret, typename... Ts>
struct Foo<Ret(Ts...)> {
    Ret Method(Ts...) const { /* .. */ }
};

// C-ellipsis (printf-like)
template <typename Ret, typename... Ts>
struct Foo<Ret(Ts..., ...)> {
    Ret Method(Ts..., ...) const { /* .. va_arg and co */ }
};

For methods, the combination is bigger (cv-qualifier (x4), ref-qualifier (x3), so 24).

Jarod42
  • 203,559
  • 14
  • 181
  • 302