1

I have been searching through SO, and other forums looking for a way to determine the parameters and return type of a lambda, and then act on those parameters in order to do a type lookup on a repo of objects that have already been instantiated. The point is to create a way to do dependency injection on some arbitrarily defined lambda expression. For instance, if I have something like the following:

auto lambda = [] (MyObject o) -> string { return o.name(); };

I could determine the parameter types of the lambda, and lookup a corresponding object of type MyObject, and then call lambda passing that object "automagically".

So far, I've found ways to determine the lambdas parameter list types and return types by using the following templates:

template <typename T>
struct function_traits
    : public function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
    // we specialize for pointers to member function
{
    enum { arity = sizeof...(Args) };
    // arity is the number of arguments.

    typedef ReturnType result_type;

    template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
        // the i-th argument is equivalent to the i-th tuple element of a tuple
        // composed of those arguments.
    };
};

Which I found in this SO post (very neat).

Now, what I'd like to do, is implement some sort of compile time equivalent of the following:

// first get the type of the lambda using the above 'function_traits' template
typedef function_traits<decltype(lambda)> traits;
// now iterate over the traits and get the type of each argument, then print out the type name
for (size_t i = 0u; i < size_t(traits::arity); ++i)
{
  // The point to focus on here is `traits::args<i>::type`
  std::cout << typeid(traits::args<i>::type).name() << std::end;
}

What I've posted above is impossible. The issue in the code above is that i is not a constant, and is evaluated at run-time, as opposed to compile time (where the rest of this template magic is evaluated). I have tried a few different things to try to figure out a way to go about this (template recursion among them), but I haven't been able to find a solution that does exactly what I want.

So, the root of my question really is, how do you "iterate" over a template? I am new to TMP, and making the mental shift from run-time to compile-time logic has been challenging. If anyone has some suggestions for a newbie that would be great.

Community
  • 1
  • 1
pje
  • 2,458
  • 1
  • 25
  • 26
  • 1
    Looping in general you can accomplish with a `template class Loop { ... }` that delegates to `Loop` for the next iteration, and a specialization `template class Loop { ... }` for the terminating case, but I'd have to dive a bit deeper into the problem in order to figure out how to apply it to this case. – cdhowie Sep 25 '14 at 20:13
  • There are two typical approaches to this problem: Recursion and pack expansion using the indices trick. You do not tell us what problems you had with recursion or what you have tried with recursion unfortunately. For the indices trick, see e.g. http://stackoverflow.com/a/7858971 – dyp Sep 25 '14 at 20:25
  • You can even find several questions titled "Iterate over tuple" or similar at SO, e.g. http://stackoverflow.com/q/1198260 – dyp Sep 25 '14 at 20:27

1 Answers1

1

With C++14, you may do:

namespace detail
{
    template <typename T, std::size_t ... Is>
    void display(std::index_sequence<Is...>)
    {
        std::initializer_list<int>{((std::cout << typeid(typename T::template arg<Is>::type).name() << std::endl), 0)...};
    }

}

template <typename T>
void display()
{
    detail::display<T>(std::make_index_sequence<T::arity>());
}

And use it:

using traits = function_traits<decltype(lambda)>;

display<traits>();

Live example

If your stuck with C++11, there is many place to find implementation of make_index_sequence and index_sequence

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • +1 Thanks for your answer, but this doesn't quite do the trick. It is closer to what I want than what was doing, but I am looking for a way to get at the types of each parameter in the lambda, so that I can do type look-ups. I might have misled you a bit with my usage example. I am going to dig more into `index_sequence` though! – pje Sep 26 '14 at 21:55