Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What else do I need to use variadic template inheritance to create lambda overloads?

I understand the basic concept of using the recursive nature of variadic template parameters and a specific template instantiation to sort of "eat" my way through the parameter list, one by one.

I understand that lambdas can be written to take certain types and then return certain types. Keep in mind that I'm still learning C++14 and C++11, so I haven't mastered one or the other.

Here was my attempt after at looking at other Stack Overflow questions:

// For std::string
#include <string>

// For std::cout
#include <iostream>


//Create a generalized list instantiation
template <typename ... F>
struct overload : public F... {
    overload(F... f) : F(f)... {}
};      

//Create an specific end-case, where we directly
//inherit the () operator in order to inherit
//multiple () overloads
template <typename F>
struct overload : F {
    using F::operator();
};


//template function to create an overload
template <class... F>
auto make_overload(F... f) {
    return (f...);
}

int main() {
    auto f = [](int x,int y) -> int {
        return x+y;
    };
    auto g = [](double x,double y) -> int {
        return std::ftoi(x+y);
    };
    auto h = [](std::string x,std::string y) -> int {
        return std::stoi(x+y);
    };

    //Ah, but this is a function.
    auto fgh = make_overload(f,g,h);

    std::cout << (fgh(1,2)) << std::endl;
    std::cout << (fgh(1.5,2.5)) << std::endl;
    std::cout << (fgh("bob","larry")) << std::endl;
}

Coliru: http://coliru.stacked-crooked.com/a/5df2919ccf9e99a6

What am I conceptually missing here? Other answers might succinctly answer this problem at face value, but I'm looking for an explanation why the answer eludes my thinking. If I understand that I need to do using F::operator() to inherit the operators and I correctly state that the return and parameter types are different, what else do I need to do to make this work?

Here's my train of thought:

  1. Create a general variadic template base class.
  2. Create a specific template case to overload a specific lambda's operator().
  3. Create a helper function to take a variadic template argument list and then use it to construct the "overload" class.
  4. Ensure that the types are unambiguous.
like image 311
CinchBlue Avatar asked May 18 '15 05:05

CinchBlue


1 Answers

You didn't actually recurse.

// primary template; not defined.
template <class... F> struct overload;

// recursive case; inherit from the first and overload<rest...>
template<class F1, class... F>
struct overload<F1, F...> : F1, overload<F...> {
    overload(F1 f1, F... f) : F1(f1), overload<F...>(f...) {}

    // bring all operator()s from the bases into the derived class
    using F1::operator();
    using overload<F...>::operator();
};      

// Base case of recursion
template <class F>
struct overload<F> : F {
    overload(F f) : F(f) {}
    using F::operator();
};
like image 127
T.C. Avatar answered Sep 23 '22 15:09

T.C.