c++templatesc++11lambdaconceptual-model

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.

Solution

  • 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();
    };