I've got an function that iterates over a container and passes each element to a predicate for filtering. An overload of this function also passes the index of each element into the predicate.
template<typename TContainer>
void DoSomethingIf(TContainer &c, std::function<bool (const typename TContainer::const_reference)> predicate);
template<typename TContainer>
void DoSomethingIf(TContainer &c, std::function<bool (const typename TContainer::const_reference, int)> predicate);
I have found that attempting to call either of these functions with a naked lambda will cause a compiler error in VC11, while using a std::function object will succeed:
void foo()
{
std::vector<int> v;
// fails
DoSomethingIf(v, [](const int &x) { return x == 0; });
// also fails
auto lambda = [](const int &x) { return x == 0; };
DoSomethingIf(v, lambda);
// success!
std::function<bool (const int &)> fn = [](const int &x) { return x == 0; };
DoSomethingIf(v, fn);
}
1>c:\users\moswald\test.cpp(15): error C2668: 'DoSomethingIf' : ambiguous call to overloaded function
1> c:\users\moswald\test.cpp(8): could be 'void DoSomethingIf<std::vector<_Ty>>(TContainer &,std::function<_Fty>)'
1> with
1> [
1> _Ty=int,
1> TContainer=std::vector<int>,
1> _Fty=bool (const int &,int)
1> ]
1> c:\users\moswald\test.cpp(5): or 'void DoSomethingIf<std::vector<_Ty>>(TContainer &,std::function<_Fty>)'
1> with
1> [
1> _Ty=int,
1> TContainer=std::vector<int>,
1> _Fty=bool (const int &)
1> ]
1> while trying to match the argument list '(std::vector<_Ty>, foo::<lambda_8EADDE04A8D35A3C>)'
1> with
1> [
1> _Ty=int
1> ]
1>c:\users\moswald\test.cpp(19): error C2668: 'DoSomethingIf' : ambiguous call to overloaded function
1> c:\users\moswald\test.cpp(8): could be 'void DoSomethingIf<std::vector<_Ty>>(TContainer &,std::function<_Fty>)'
1> with
1> [
1> _Ty=int,
1> TContainer=std::vector<int>,
1> _Fty=bool (const int &,int)
1> ]
1> c:\users\moswald\test.cpp(5): or 'void DoSomethingIf<std::vector<_Ty>>(TContainer &,std::function<_Fty>)'
1> with
1> [
1> _Ty=int,
1> TContainer=std::vector<int>,
1> _Fty=bool (const int &)
1> ]
1> while trying to match the argument list '(std::vector<_Ty>, foo::<lambda_8EADDE04A8D35A3D>)'
1> with
1> [
1> _Ty=int
1> ]
Is this to be expected? Is there a different way to overload these functions (short of renaming one to be "DoSomethingIfWithIndex
"?
The overload ambiguity is expected.
std::function
has a converting constructor template that accepts any argument. Only after the constructor template is instantiated can the compiler determine that it will reject the argument.
In both your first and second examples, a user-defined conversion is required to convert the unspecified lambda type to each of the std::function
types. Neither conversion is better (they are both user-defined conversions), so the compiler reports the overload ambiguity.
In your third example (the one that works), there is no ambiguity because the std::function
constructor template is not used. Instead, its copy constructor is used (and, all other things being equal, nontemplates are preferred over templates).