Is it possible to determine the type of parameter and return type of polymorphic C ++ 14 lambda?

Starting from this question ( Is it possible to find out the type of the parameter and the return type of the lambda? ) I used the proposed function_traits lot. However, with C ++ 14 polymorphic lambdas arrived, and they gave me a hard time.

 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. }; }; 

operator() , as suggested in another answer to the question, is now overloaded, as specified in the standard for support:

 auto lambda1 = [](auto& a) { a.foo(); } 

and

 auto lambda2 = [](auto&&... args) { foo(args...); }; 

This overload now breaks the function_traits class because the compiler cannot resolve the correct version of operator() .

 lambda.cpp:98:38: error: reference to overloaded function could not be resolved; did you mean to call it? typedef function_traits<decltype(&T::operator())> caller; 

Is it somehow possible to achieve function_traits function_traits for polymorphic lambda with C ++ 14?

+5
source share
2 answers

Currently, this cannot be done in a general sense, but if your lambdas have cars for all their parameters and work with all of them replaced by some known type, you can change the answer to this question: C ++ metafunction to define whether the type is callable

Along the lines

 static const bool OneArg = (sizeof( test<T, int>(0) ) == 1); static const bool TwoArg = (sizeof( test<T, int, int>(0) ) == 1); static const bool ThreeArg = (sizeof( test<T, int, int, int>(0) ) == 1); static constexpr std::size_t TemplatedOperatorArgSize = OneArg ? 1 : TwoArg ? 2 : ThreeArg ? 3 : -1; 

Apologies for the nested trinity. And then use something like this to call it:

 template<size_t N, typename T> struct Apply { template<typename F, typename... A> static inline decltype(auto) apply(F && f, A &&... a) { return Apply<N-1, T>::apply(::std::forward<F>(f), std::declval<T>(), ::std::forward<A>(a)...); } }; template<typename T> struct Apply<0, T> { template<typename F, typename... A> static inline decltype(auto) apply(F && f, A &&... a) { return invoke(std::forward<F>(f), std::forward<A>(a)...); } }; template<std::size_t Size, typename T, typename F> inline decltype(auto) apply(F && f) { return Apply<Size, T>::apply(::std::forward<F>(f)); } 

Using invoke from: http://en.cppreference.com/w/cpp/utility/functional/invoke

Get return type

 using return_type = decltype( apply<has_callable_operator<T>::TemplatedOperatorArgSize, int>(function) ); 

The first part can be rewritten to deal with an arbitrary number of arguments using std::make_index_sequence

But as a rule, I would say that you go down the rabbit hole. Good luck.

Note. Did not check the code used, but it should be good enough for you to get started.

Edit: In addition, the return type must be independent of the parameter types in order to achieve the desired

+1
source

I had a similar case when implementing Cache with the Fetch function. Sort of:

 template<class KEY, class VALUE, class FetchFunctor> class Cache { ... }; 

Phase 1

I wanted to save the user to indicate the type of his / her FetchFunctor and without the C ++ 17 class template argument argument, I went for the createCahce helper method, like this:

 // [1] template<class KEY, class VALUE, class FetchFunctor> auto createCache(FetchFunctor fetchFunctor) { return Cache<KEY, VALUE, FetchFunctor>(fetchFunctor); } 

Thus, creating a cache is quite simple, for example:

 auto cache = createCache<int, int>([](int i){return i+3;}); 

Phase 2

It would be much better to allow the user to create a cache without having to provide the Key and Value types of the cache and deduce them as provided by the FetchFunctor . Therefore, I added an additional createCache method :

 // [2] template<class FetchFunctor> auto createCache(FetchFunctor fetchFunctor) { // function_traits is a namespace where I 'hide' the // traits structs for result type and arguments type deduction using f = function_traits::traits<decltype(fetchFunctor)>; using KEY = typename f::template arg<0>::type; using VALUE = typename f::result_type; return Cache<KEY, VALUE, FetchFunctor>(fetchFunctor); } 

Now creating a cache is even easier:

 auto cache = createCache([](int i){return i+3;}); 

But can both the createCache methods above live together?

Fortunately, yes.

  • If the user provides the arguments to the Key, Value template, then the first one is the only one.
  • If the user does not provide template arguments, the compiler treats the second as "more specialized" and prefers it.

Thus, we can support all of the cases below:

  // [a] auto cache = createCache([](int i){return i+3;}); // compiler deduces Key, Value to be: int, int - using the 2nd createCache // [b] auto cache = createCache<int, int>([](auto i){return i+3;}); // we have a generic lambda so we provide Key and Value - using the 1st createCache // [c] auto cache = createCache<string, string>( [](const char* s){return string(s) + '!';} ); // we want different Key and/or Value than would be deduced - we use 1st createCache 

Yet...

The following commands will not compile:

  auto cache = createCache([](auto i){return i+3;}); // we cannot deduce types for generic lambda // compiler goes to the 2nd createCache but Key and Value cannot be deduced // - compilation error 

But this should not bother us ... you can provide the key and value, as in [b] above.


the code:

http://coliru.stacked-crooked.com/a/e19151a5c245d7c3

+1
source

Source: https://habr.com/ru/post/1211755/


All Articles