C ++ 11은 std :: function 또는 lambda 함수가 관련된 경우 유형을 추론하지 않습니다.
이 함수를 정의 할 때
template<class A>
set<A> test(const set<A>& input) {
return input;
}
test(mySet)
템플릿 유형을 명시 적으로 정의하지 않고도 코드의 다른 곳에서 호출 할 수 있습니다 . 그러나 다음 기능을 사용하는 경우 :
template<class A>
set<A> filter(const set<A>& input,function<bool(A)> compare) {
set<A> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret.insert(*it);
}
}
return ret;
}
이 함수를 사용하여 호출 filter(mySet,[](int i) { return i%2==0; });
하면 다음 오류가 발생합니다.
오류 : 'filter (std :: set &, main () : :)'호출에 일치하는 함수가 없습니다.
그러나 다음 버전 은 모두 작동합니다.
std::function<bool(int)> func = [](int i) { return i%2 ==0; };
set<int> myNewSet = filter(mySet,func);
set<int> myNewSet = filter<int>(mySet,[](int i) { return i%2==0; });
set<int> myNewSet = filter(mySet,function<bool(int)>([](int i){return i%2==0;}));
람다 함수를 직접 만들지 않고 식 안에 직접 넣을 때 C ++ 11이 템플릿 유형을 추측 할 수없는 이유는 무엇 std::function
입니까?
편집하다:
주석에있는 Luc Danton의 조언에 따라, 여기에 템플릿을 명시 적으로 전달할 필요가없는 이전 기능의 대안이 있습니다.
template<class A,class CompareFunction>
set<A> filter(const set<A>& input,CompareFunction compare) {
set<A> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret.insert(*it);
}
}
return ret;
}
set<int> result = filter(myIntSet,[](int i) { i % 2 == 0; });
템플릿이 없어도에서 호출 할 수 있습니다 .
컴파일러는 새로운 decltype 키워드와 새로운 함수 반환 유형 구문을 사용하여 반환 유형을 어느 정도 추측 할 수도 있습니다. 다음은 하나의 필터링 함수와 값을 기반으로 키를 생성하는 하나의 함수를 사용하여 집합을 맵으로 변환하는 예입니다.
template<class Value,class CompareType,class IndexType>
auto filter(const set<Value>& input,CompareType compare,IndexType index) -> map<decltype(index(*(input.begin()))),Value> {
map<decltype(index(*(input.begin()))),Value> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret[index(*it)] = *it;
}
}
return ret;
}
템플릿을 직접 사용하지 않고 다음과 같이 호출 할 수도 있습니다.
map<string,int> s = filter(myIntSet,[](int i) { return i%2==0; },[](int i) { return toString(i); });
문제는 람다의 특성에 있습니다. 표준에 따라 고정 된 속성 집합이있는 함수 개체이지만 함수 는 아닙니다 . 표준은 람다가 std::function<>
정확한 유형의 인수와 상태가없는 경우 함수 포인터 로 변환 될 수 있다고 결정합니다 .
그러나 이것이 람다가 std::function
함수 포인터도 아니라는 것을 의미하지는 않습니다 . 그들은 구현하는 고유 한 유형 operator()
입니다.
반면 유형 추론은 변환없이 정확한 유형 만 추론합니다 (const / volatile 제한 제외). 람다가 아닌 있기 때문에 std::function
컴파일러는 호출 유형을 추론 할 수 없습니다 filter(mySet,[](int i) { return i%2==0; });
어떤로 std::function<>
인스턴스화.
다른 예제와 마찬가지로 첫 번째 예제에서는 람다를 함수 유형으로 변환 한 다음 전달합니다. 컴파일러 std::function
는가 동일한 유형의 rvalue (임시) 인 세 번째 예제에서와 같이 유형을 추론 할 수 있습니다 .
인스턴스화 유형 int
을 템플릿에 제공하면 두 번째 작업 예제 인 추론이 작동하지 않습니다. 컴파일러는 유형을 사용한 다음 람다를 적절한 유형으로 변환합니다.
사건은 잊어 버려 분석하기에는 너무 복잡합니다.
이 간단한 예를 들어 보자 :
template<typename T>
struct X
{
X(T data) {}
};
template<typename T>
void f(X<T> x) {}
이제 다음 f
과 같이 호출하십시오 .
f(10);
여기에서 당신은 생각하는 유혹 수도 T
로 추론 할 것입니다 int
및 따라서 위의 함수 호출이 작동합니다. 음, 그렇지 않습니다. 간단하게하기 위해 다음과 같은 다른 생성자 가 있다고 상상해보십시오 int
.
template<typename T>
struct X
{
X(T data) {}
X(int data) {} //another constructor
};
이제 T
내가 글을 쓸 때 무엇 을 추론해야 f(10)
합니까? 음, T
할 수 있는 유형.
다른 많은 경우가있을 수 있습니다. 예를 들어이 전문화를 취하십시오.
template<typename T>
struct X<T*> //specialized for pointers
{
X(int data) {};
};
Now what T
should be deduced to for the call f(10)
? Now it seems even harder.
It is therefore non-deducible context, which explains why your code doesn't work for std::function
which is an identical case — just looks complex at the surface. Note that lambdas are not of type std::function
— they're basically instances of compiler generated classes (i.e they're functors of different types than std::function
).
If we have:
template <typename R, typename T>
int myfunc(std::function<R(T)> lambda)
{
return lambda(2);
}
int r = myfunc([](int i) { return i + 1; });
It will not compile. But if you previously declare:
template <typename Func, typename Arg1>
static auto getFuncType(Func* func = nullptr, Arg1* arg1 = nullptr) -> decltype((*func)(*arg1));
template <typename Func>
int myfunc(Func lambda)
{
return myfunc<int, decltype(getFuncType<Func, int>())>(lambda);
}
You can call your function with a lambda parameter without problem.
There are 2 new pieces of code here.
First, we have a function declaration which is only useful to return an old-style function pointer type, based on given template parameters:
template <typename Func, typename Arg1>
static auto getFuncType(Func* func = nullptr, Arg1* arg1 = nullptr) -> decltype((*func)(*arg1)) {};
Second, we have a function that takes a template argument to build our expected lambda type calling 'getFuncType':
template <typename Func>
int myfunc(Func lambda)
{
return myfunc<int, decltype(getFuncType<Func, int>())>(lambda);
}
With the correct template parameters, now we can call the real 'myfunc'. Complete code will be:
template <typename R, typename T>
int myfunc(std::function<R(T)> lambda)
{
return lambda(2);
}
template <typename Func, typename Arg1>
static auto getFuncType(Func* func = nullptr, Arg1* arg1 = nullptr) -> decltype((*func)(*arg1)) {};
template <typename Func>
int myfunc(Func lambda)
{
return myfunc<int, decltype(getFuncType<Func, int>())>(lambda);
}
int r = myfunc([](int i) { return i + 1; });
You can declare any overload for 'getFuncType' to match your lambda parameter. For example:
template <typename Func, typename Arg1, typename Arg2>
static auto getFuncType(Func* func = nullptr, Arg1* arg1 = nullptr, Arg2* arg2 = nullptr) -> decltype((*func)(*arg1, *arg2)) {};
ReferenceURL : https://stackoverflow.com/questions/9998402/c11-does-not-deduce-type-when-stdfunction-or-lambda-functions-are-involved
'programing' 카테고리의 다른 글
단항 더하기 및 빼기 연산자의 중요한 용도는 무엇입니까? (0) | 2021.01.15 |
---|---|
Visual Studio 2010에서 병렬 빌드를 수행하려면 어떻게해야합니까? (0) | 2021.01.15 |
녹아웃 : 계산 된 관찰 가능 vs 함수 (0) | 2021.01.15 |
PDO bindParam 대 실행 (0) | 2021.01.15 |
모니터 (DDMS) 도구를 사용하여 애플리케이션을 디버그하는 방법 (0) | 2021.01.15 |