2

I'm having troubles implementing this in legacy C++, but I'm pretty sure it can be done. Say I have a higher order function that needs two versions, one for unary callables (function objects, functions, member functions)

template <class F>
void ho_fun(F argFun) { 
    int arg1; 
    argFun(arg1); 
}

and one for binary:

template <class F>
void ho_fun(F argFun) { 
    int arg1, arg2; 
    argFun(arg1, arg2); 
}

I'm looking for a complete solution in terms of "callable type" (otherwise I'd obviously use arity from function traits for this) i.e. support for functions and function objects.

I'm translating this lovely post to C++03 (remove ... and using typedefs) but it doesn't seem to work.

PS. I'm not solving the particular problem listed above, that's just the sscce. Also I mention C++03 because I'm working on legacy code for this project and a modern solution is of no use to me. By all means feel free to post a modern one but please consider helping me as well.

Lorah Attkins
  • 5,331
  • 3
  • 29
  • 63
  • I don't get it. The code in the question does not work but you don't want to know what is wrong with it anyway? – NathanOliver Feb 20 '17 at 13:32
  • The right way to do this is varadics. Why are you trying to get rid of the `...`s? – Jonathan Mee Feb 20 '17 at 13:33
  • @NathanOliver Usually my examples are mistaken for the actual problem I want to solve. The actual problem is "dispatch for unary and binary code", I'm mentioning the PS to avoid answers like "pass another argument" or "create an extra overload" – Lorah Attkins Feb 20 '17 at 13:34
  • @LorahAttkins Aha. Just got it. Can you use boost? I think they have something built for this in C++03. – NathanOliver Feb 20 '17 at 13:35
  • @JonathanMee Because the environment I'm working on (about 3M lines of legacy C++ code) uses a C++03 compiler and variadics were only introduced in C++11 – Lorah Attkins Feb 20 '17 at 13:36
  • How about boost::function::arity? This is C++03... – Christopher Oezbek Feb 20 '17 at 13:36
  • I'm mentioning `arity` in the question. Arity does not support function objects, last I check it only works for free functions and this I have implemented already (it's simple pattern matching with template specializations) – Lorah Attkins Feb 20 '17 at 13:38
  • @LorahAttkins From the example you've shown you're just passing some unknown arguments into a function pointer passed to the code. That's obviously not useful code. can you provide more information on what you want `ho_fun` to accomplish? There are other ways around this, but without more information from you choosing one would be impossible. – Jonathan Mee Feb 20 '17 at 13:49
  • @JonathanMee You can look at it as a thought experiment. The abstract is preety clear: "Can you create a metaprogram to discover the arity of a callable?". Me asking for dispatching based on unary or binary callables, is already a workaround. – Lorah Attkins Feb 20 '17 at 13:52
  • @LorahAttkins So you're not looking to call the function? You simply want to take in a function pointer and return whether it requires 1 or 2 arguments? You're not trying to actually have `ho_fun` call anything? – Jonathan Mee Feb 20 '17 at 13:57
  • @JonathanMee I want ho_fun to vary its behavior based on the arity of the callable we'll pass to it. Of course I'll be calling the function argument, but unless I correctly dispatch there's a compilation error. – Lorah Attkins Feb 20 '17 at 14:00
  • 1
    I'd go to [here](http://stackoverflow.com/a/10707822/2412846) and check whether the function is unary or binary. On base of this, I'd SFINAE-out the inappropriate version. – davidhigh Feb 20 '17 at 14:42
  • I seem to recall having tackled a similar problem some time ago while running tests for `cxxomfort`'s tuple and function traits, but I'd have to search through to find the code. The most important limitation I remember is that in order to work it needed something like `__typeof` to be available; at that point, it's just a matter of explicitly specializing the required arities (because C++03 lacks variadics) and constnesses (for member functions, etc) for the "function object" case. – Luis Machuca Feb 21 '17 at 02:50
  • 1
    There is no way in to ask C++03 questions like "are objects of this type callable with these arguments?" You can only ask "is this a function type with this exact signature" or "is this a class type that has operator() with this exact signature?" – n. m. could be an AI Feb 21 '17 at 13:21

1 Answers1

1

This answer provides a solution to the question I understand you to be asking:

How can I specialize a function so that it can detect whether it's argument is a unary or binary function, method, or functor?

In your only option is to write specializations for each of these, and incidentally you'll need to make specializations for const methods as well as non-const methods:

template <typename Arg, typename Result>
void ho_fun(Result(*argFun)(Arg)) {
    Arg arg = 13;

    argFun(arg);
}

template <typename Arg1, typename Arg2, typename Result>
void ho_fun(Result (*argFun)(Arg1, Arg2)) {
    Arg1 arg1 = 13;
    Arg2 arg2 = 42;

    argFun(arg1, arg2);
}

template <typename T, typename Arg, typename Result>
void ho_fun(Result(T::*argFun)(Arg)) {
    T myClass;
    Arg arg = 13;

    (myClass.*argFun)(arg);
}

template <typename T, typename Arg1, typename Arg2, typename Result>
void ho_fun(Result(T::*argFun)(Arg1, Arg2)) {
    T myClass;
    Arg1 arg1 = 13;
    Arg2 arg2 = 42;

    (myClass.*argFun)(arg1, arg2);
}

template <typename T, typename Arg, typename Result>
void ho_fun(Result(T::*argFun)(Arg) const) {
    T myClass;
    Arg arg = 13;

    (myClass.*argFun)(arg);
}

template <typename T, typename Arg1, typename Arg2, typename Result>
void ho_fun(Result(T::*argFun)(Arg1, Arg2) const) {
    T myClass;
    Arg1 arg1 = 13;
    Arg2 arg2 = 42;

    (myClass.*argFun)(arg1, arg2);
}

template <class T>
void ho_fun(T argFun) {
    ho_fun(&T::operator());
}

Live Example

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288