2

I met some similar problem and find this question: Is it possible to figure out the parameter type and return type of a lambda?.

I use the code in the answer of that question:

#include <iostream>
#include <tuple>

template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())> {}; 

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
  enum { arity = sizeof...(Args) };

  typedef ReturnType result_type;

  template <size_t i>
  struct arg {   
  typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
  };  
};

In my case, the (lambda)function is user-defined, so I must use a template function to do something based on the user-defined function, so I add a proxy function below:

template <class F>
void proxy(F func) {
  typedef function_traits<decltype(func)> traits;
  typename traits::result_type r;
  traits::arg<0>::type p;                          // compile error
}

I get the compiling error below:

error: `::type` has not been declared
error: expected `;` before `p`

Why return type can be compiled while parameter type can not, how can I make it work?

Community
  • 1
  • 1
xunzhang
  • 2,838
  • 6
  • 27
  • 44

1 Answers1

9

Use typename and template:

typename traits::template arg<0>::type p;    

One line explanations:

  • Why typename? Because ::type is a dependent type.
  • Why template? Because arg<> is a dependent template.

Hope that helps.

Ajay
  • 18,086
  • 12
  • 59
  • 105
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    +1: An outstanding diatribe on usage of `template` and `typename` [can be found here](http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords). – WhozCraig Jan 22 '14 at 16:46
  • @Nawaz what if p is a `reference` type? – xunzhang Mar 06 '14 at 08:22
  • @xunzhang: I didn't understand what you're asking. Let me explain : `p` is a variable, not a type, its type is `typename traits::template arg<0>::type` which could be a reference. So what is your question? – Nawaz Mar 06 '14 at 08:26
  • @Nawaz My question is that if `typename traits::template arg<0>::type` is a reference type, I want to convert it a the original type. For exampe, if `typename traits::template arg<0>::type` is `const vector&`, I want to convert it to `vector` – xunzhang Mar 06 '14 at 08:39
  • @xunzhang: Use `std::remove_cv` and `std::remove_reference`. Example : `typename std::remove_cv::type>::type p;`. Ugly but it does the job! You could improve the usage, if you wrap it in an alias as `template using bare_type = typename std::remove_cv::type>::type;` ... then `bare_type p;` would be the syntax. – Nawaz Mar 06 '14 at 08:41