简体   繁体   中英

Practical C++ Metaprogramming

I just read the book "Practical C++ Metaprogramming" and it has the following example that I cannot compile. Can you help sort this out for me.

template <typename F>
struct make_tuple_of_params;

template <typename Ret, typename... Args>
struct make_tuple_of_params<Ret (Args...)>
{
   using type = std::tuple<Args...>;
};

template <typename F>
using make_tuple_of_params_t = typename make_tuple_of_params<F>::type;

template<typename F>
void some_magic_function(F callable)
{
   make_tuple_of_params_t<F> tuple;
   /*
    ... do something with arguments in tuple...
   */
}

int main()
{
   some_magic_function([] (int, double, float) {});
}

I get a compilation error saying: 'type' is not a member of any direct or indirect base class of 'make_tuple_of_params'. It seams like the SFINAE does not work as expected since the default struct is selected. How do I fix this?

The type of [] (int, double, float) {} is an unnamed class type local to main , called the closure type. It is most definitely not void (int, double, float) ; it is in fact not a function type at all. Therefore, the specialisation for function types doesn't apply, and the primary template is selected. (Note that no SFINAE is involved in your code).

As for how to fix this: I don't think there's a fully general solution. There could be a solution/workaround for a particular some_magic_function , but that would depend on what you need that function to do.

For lambdas if not including lambdas with auto parameters the workaround could look as follows:

#include <tuple>
#include <typeinfo>
#include <iostream>

template <class>
struct make_tuple_of_params;

template <class Res, class Type, class... Args>
struct make_tuple_of_params<Res (Type::*)(Args...) const> {
    using type = std::tuple<Args...>;
};

template <class F>
using make_tuple_of_params_t = typename make_tuple_of_params<F>::type;

template<typename F>
void some_magic_function(F callable)
{
   make_tuple_of_params_t<decltype(&F::operator())> tuple;
   std::cout << typeid(tuple).name() << std::endl;
}

int main()
{
   some_magic_function([] (int, double, float) {});
}

[live demo]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM