람다의 매개 변수 유형과 반환 유형을 알아낼 수 있습니까?
람다가 주어지면 매개 변수 유형과 반환 유형을 알아낼 수 있습니까? 그렇다면 어떻게?
기본적으로 lambda_traits
다음과 같은 방식으로 사용할 수 있습니다.
auto lambda = [](int i) { return long(i*10); };
lambda_traits<decltype(lambda)>::param_type i; //i should be int
lambda_traits<decltype(lambda)>::return_type l; //l should be long
뒤에 동기 lambda_traits
는 람다를 인수로 받아들이는 함수 템플릿에서 사용하고 싶습니다 . 함수 내의 매개 변수 유형과 반환 유형을 알아야합니다.
template<typename TLambda>
void f(TLambda lambda)
{
typedef typename lambda_traits<TLambda>::param_type P;
typedef typename lambda_traits<TLambda>::return_type R;
std::function<R(P)> fun = lambda; //I want to do this!
//...
}
당분간 우리는 람다는 정확히 하나의 주장을 취한다고 가정 할 수 있습니다.
처음에는 std::function
다음 과 같이 작업하려고 했습니다.
template<typename T>
A<T> f(std::function<bool(T)> fun)
{
return A<T>(fun);
}
f([](int){return true;}); //error
그러나 분명히 오류가 발생합니다. 그래서 TLambda
함수 템플릿의 버전으로 변경 하고 함수 std::function
안에 객체 를 구성하려고 합니다 (위 그림 참조).
재미있게, 방금 매개 변수 유형을 제공 할 수 있는 C ++ 0x의 람다에서 템플릿을 전문화하는 것을 기반으로 function_traits
구현을 작성했습니다 . 그 질문에 대한 답변에서 설명한 것처럼 트릭 은 람다의 를 사용하는 것 입니다 . decltype
operator()
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.
};
};
// test code below:
int main()
{
auto lambda = [](int i) { return long(i*10); };
typedef function_traits<decltype(lambda)> traits;
static_assert(std::is_same<long, traits::result_type>::value, "err");
static_assert(std::is_same<int, traits::arg<0>::type>::value, "err");
return 0;
}
이 솔루션 은 일반적인 람다 에서는 작동 하지 않습니다[](auto x) {}
.
이것이 엄격하게 표준을 준수하는지 확실하지 않지만 ideone 은 다음 코드를 컴파일했습니다.
template< class > struct mem_type;
template< class C, class T > struct mem_type< T C::* > {
typedef T type;
};
template< class T > struct lambda_func_type {
typedef typename mem_type< decltype( &T::operator() ) >::type type;
};
int main() {
auto l = [](int i) { return long(i); };
typedef lambda_func_type< decltype(l) >::type T;
static_assert( std::is_same< T, long( int )const >::value, "" );
}
그러나 이는 함수 유형 만 제공하므로 결과 및 매개 변수 유형을 추출해야합니다. 당신이 사용할 수있는 경우 boost::function_traits
, result_type
그리고 arg1_type
목적을 충족합니다. C ++ 11 모드에서 ideone이 부스트를 제공하지 않는 것 같으므로 실제 코드를 게시 할 수 없습니다. 죄송합니다.
The specialization method shown in @KennyTMs answer can be extended to cover all cases, including variadic and mutable lambdas:
template <typename T>
struct closure_traits : closure_traits<decltype(&T::operator())> {};
#define REM_CTOR(...) __VA_ARGS__
#define SPEC(cv, var, is_var) \
template <typename C, typename R, typename... Args> \
struct closure_traits<R (C::*) (Args... REM_CTOR var) cv> \
{ \
using arity = std::integral_constant<std::size_t, sizeof...(Args) >; \
using is_variadic = std::integral_constant<bool, is_var>; \
using is_const = std::is_const<int cv>; \
\
using result_type = R; \
\
template <std::size_t i> \
using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; \
};
SPEC(const, (,...), 1)
SPEC(const, (), 0)
SPEC(, (,...), 1)
SPEC(, (), 0)
Demo.
Note that the arity is not adjusted for variadic operator()
s. Instead one can also consider is_variadic
.
The answer provided by @KennyTMs works great, however if a lambda has no parameters, using the index arg<0> does not compile. If anyone else was having this problem, I have a simple solution (simpler than using SFINAE related solutions, that is).
Just add void to the end of the tuple in the arg struct after the variadic argument types. i.e.
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...,void>>::type type;
};
since the arity isn't dependent on the actual number of template parameters, the actual won't be incorrect, and if it's 0 then at least arg<0> will still exist and you can do with it what you will. If you already plan to not exceed the index arg<arity-1>
then it shouldn't interfere with your current implementation.
'programing tip' 카테고리의 다른 글
왜 메이븐? (0) | 2020.07.01 |
---|---|
pip 요구 사항 파일에 주석을 추가 할 수 있습니까? (0) | 2020.07.01 |
127.0.0.1과 localhost의 차이점은 무엇입니까 (0) | 2020.07.01 |
Android Studio에는 Android-L Mac 용 JDK 7이 필요합니다 (0) | 2020.06.30 |
jquery를 사용하여 페이지의 특정 위치로 스크롤하려면 어떻게해야합니까? (0) | 2020.06.30 |