The short version of my question is this: How can I use something like std::bind() with a standard library algorithm?
Since the short version is a bit devoid of details, here is a bit of an explanation: Assume I have the algorithms std::transform() and now I want to implement std::copy() (yes, I realize that there is std::copy() in the standard C++ library). Since I'm hideously lazy, I clearly want to use the existing implementation of std::transform(). I could, of course, do this:
struct identity {
template <typename T>
auto operator()(T&& value) const -> T&& { return std::forward<T>(value); }
};
template <typename InIt, typename OutIt>
auto copy(InIt begin, InIt end, OutIt to) -> OutIt {
return std::transform(begin, end, to, identity());
}
Somehow this implementation somewhat feels like a configuration of an algorithm. For example, it seems as if std::bind() should be able to do the job but simply using std::bind() doesn't work:
namespace P = std::placeholders;
auto copy = std::bind(std::transform, P::_1, P::_2, P::_3, identity());
The problem is that the compiler can't determine the appropriate template arguments from just the algorithm and it doesn't matter if there is an & or not. Is there something which can make an approach like using std::bind() work? Since this is looking forward, I'm happy with a solution working with anything which is already proposed for inclusion into the C++ standard. Also, to get away with my laziness I'm happy to do some work up front for later easier use. Think of it this way: in my role as a library implementer, I'll put things together once such that every library user can be lazy: I'm a busy implementer but a lazy user.
In case you want to have a ready-made test bed: here is a complete program.
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <utility>
#include <vector>
using namespace std::placeholders;
struct identity {
template <typename T>
T&& operator()(T&& value) const { return std::forward<T>(value); }
};
int main()
{
std::vector<int> source{ 0, 1, 2, 3, 4, 5, 6 };
std::vector<int> target;
#ifdef WORKS
std::transform(source.begin(), source.end(), std::back_inserter(target),
identity());
#else
// the next line doesn't work and needs to be replaced by some magic
auto copy = std::bind(&std::transform, _1, _2, _3, identity());
copy(source.begin(), source.end(), std::back_inserter(target));
#endif
std::copy(target.begin(), target.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
}
When trying to std::bind() an overloaded function the compiler can't determine which overload to use: at the time the bind()-expression is evaluated the function arguments are unknown, i.e., overload resolution can't decide which overload to pick. There is no direct way in in C++ [yet?] to treat an overload set as an object. Function templates simply generate an overload set with one overload for each possible instantiation. That is, the entire problem of not being able to std::bind() any of the standard C++ library algorithms revolves around the fact that the standard library algorithms are function templates.
One approach to have the same effect as std::bind()ing an algorithm is to use C++14 generic lambdas to do the binding, e.g.:
auto copy = [](auto&&... args){
return std::transform(std::forward<decltype(args)>(args)..., identity());
};
Although this works it is actually equivalent to a fancy implementation of function template rather than configuring an existing function. However, using generic lambdas to create the primary function objects in a suitable standard library namespace could make the actual underlying function objects readily available, e.g.:
namespace nstd {
auto const transform = [](auto&&... args){
return std::transform(std::forward<decltype(args)>(args...));
};
}
Now, with the approach to implementing transform() it is actually trivial to use std::bind() to build copy():
auto copy = std::bind(nstd::transform, P::_1, P::_2, P::_3, identity());
Despite the looks and use of generic lambdas it is worth pointing out that it actually takes roughly the same effort to create corresponding function objects using only features available for C++11:
struct transform_t {
template <typename... Args>
auto operator()(Args&&... args) const
-> decltype(std::transform(std::forward<decltype(args)>(args)...)) {
return std::transform(std::forward<decltype(args)>(args)...);
}
};
constexpr transform_t transform{};
Yes, it is more typing but it is just a reasonable small constant factor over the use of generic lambdas, i.e., if the objects using generic lambdas the C++11 version is, too.
Of course, once we have function objects for the algorithms it may be neat to actually not even having to std::bind() them as we'd need to mention all the not bound arguments. In the example case it is currying (well, I think currying only applies to binding the first argument but whether it's the first or the last argument seems a bit random). What if we had curry_first() and curry_last() to curry the first or the last argument? The implementation of curry_last() is trivial, too (for brevity I'm using a generic lambda but the same rewrite as above could be used to make it available with C++11):
template <typename Fun, typename Bound>
auto curry_last(Fun&& fun, Bound&& bound) {
return [fun = std::forward<Fun>(fun),
bound = std::forward<Bound>(bound)](auto&&... args){
return fun(std::forward<decltype(args)>(args)..., bound);
};
}
Now, assuming that curry_last() lives in the same namespace a either nstd::transform or identity() the definition of copy() could become:
auto const copy = curry_last(nstd::transform, identity());
OK, maybe this question didn't get me any hat but maybe I'll get some support for turning our standard library algorithms into function objects and possibly adding a few cool approaches to creating bound versions of said algorithms. I think this approach is much saner (although in the form described above possibly not as complete) than some of the proposals in this area.
Related
c++14 introduced generic lambdas that made it possible to write following:
auto func = [](auto a, auto b){
return a + b;
};
auto Foo = func(2, 5);
auto Bar = func("hello", "world");
It is very clear that this generic lambda func works just like a templated function func would work.
Why did the C++ committee decide to add template syntax for generic lamda?
C++14 generic lambdas are a very cool way to generate a functor with an operator () that looks like this:
template <class T, class U>
auto operator()(T t, U u) const;
But not like this:
template <class T>
auto operator()(T t1, T t2) const; // Same type please
Nor like this:
template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; // Only `std::array` please
Nor like this (although this gets a bit tricky to actually use):
template <class T>
auto operator()() const; // No deduction
C++14 lambdas are fine, but C++20 allows us to implement these cases without hassle.
Since you can use templated lambdas in C++20, you can restrict your types in an easier way than an SFINAE expression:
auto lambda = []<typename T>(std::vector<T> t){};
This lambda will work only with vector types.
The new "familiar template syntax" for lambdas introduced in C++20
makes constructs such as for_types and for_range viable and way more
readable compared to C++17 alternatives.
(source: compile-time iteration with C++20 lambdas)
Another interesting thing that can be done on both C++14 and C++17 generic lambdas is directly calling operator() by explicitly passing a template parameter:
C++14:
auto l = [](auto){ };
l.template operator()<int>(0);
C++20 (see also the explanation for <tparams> on cppreference):
auto l = []<typename T>(){ };
l.template operator()<int>();
The C++14 example above is quite useless: there's no way of referring to the type provided to operator() in the body of the lambda without giving the argument a name and using decltype. Additionally, we're forced to pass an argument even though we might not need it.
The C++20 example shows how T is easily accessible in the body of the lambda and that a nullary lambda can now be arbitrarily templated. This is going to be very useful for the implementation of the aforementioned compile-time constructs.
The proposal that was accepted into C++20 has a lengthy motivation section, with examples. The premise of it is this:
There are a few key reasons why the current syntax for defining
generic lambdas is deemed insufficient by the author. The gist of it is
that some things that can be done easily with normal function templates
require significant hoop jumping to be done with generic lambdas, or
can’t be done at all.The author thinks that lambdas are valuable
enough that C++ should support them just as well as normal function
templates.
Following that are quite a few examples.
I have trouble understanding the order of template instantiation. It seems that the compiler does not consider a function if it is defined "too late." The following steps illustrates the main ideas of the code below:
The framework should provide a free function convert<From, To> if it can find a working overload for the function generate.
The function to<T> is a shortcut for convert<From,To> and should only work if convert<From,To> is valid.
Users should be able to provide an overload of generate and be able to use to and convert.
The corresponding code:
#include <string>
#include <utility>
#include <iostream>
// If I move the code down below at [*] to this location, everything works as
// expected.
// ------------- Framework Code -------------
// Anything that can be generated can also be converted to a string.
template <typename From>
auto convert(From const& from, std::string& to)
-> decltype(
generate(std::declval<std::back_insert_iterator<std::string>&>(), from)
)
{
to.clear();
auto i = std::back_inserter(to);
return generate(i, from);
}
// Similar to convert, except that it directly returns the requested type.
template <typename To, typename From>
auto to(From const& f) -> decltype(convert(f, std::declval<To&>()), To())
{
To t;
if (! convert(f, t))
throw std::invalid_argument("invalid conversion");
return t;
}
// ------------- User Code -------------
// [*] Support arithmetic types.
template <typename Iterator, typename T>
auto generate(Iterator& out, T i)
-> typename std::enable_if<std::is_arithmetic<T>::value, bool>::type
{
// Note: I merely use std::to_string for illustration purposes here.
auto str = std::to_string(i);
out = std::copy(str.begin(), str.end(), out);
return true;
}
int main()
{
uint16_t s = 16;
std::cout << to<std::string>(s) << std::endl;
return 0;
}
The problem in the following code is that it only works if the function generate appears before the definition of convert and to. How can I work around this problem?
Maybe my mental model is wrong here, but I thought the template when the compiler sees to<std::string>(uint16_t), it starts going backwards to and instantiate as needed. Any guidance would be appreciated.
The compiler does not know of the existence of generate by the time it sees the definition of convert and to, as you have already guessed yourself. Contrary to what you thought, it doest not though sort of put the definitions of convert and to "on hold" until it sees what generate is. To workaround this problem you need to forward declare generate, what can be done using the following construction:
template <typename Iterator, typename T>
auto generate(Iterator& out, T i)
-> typename std::enable_if<std::is_arithmetic<T>::value, bool>::type;
This should appear right before the definition of convert, so that the compiler knows generate actually exists and also is a function by the time it compiles convert and to. This way the compiler can check the syntax and guarantee it is a valid call to generate, even before it knows what generate actually does, since all it needs to do at this point is check if the types of the arguments as well as of the return value match, according to the rules defined by the language standard.
By doing this, you naturally enforce a specific type signature for generate (remember the compiler is required to check the types when it compiles convert and to!). If you don't want to do that, and you probably don't, then the best approach is to expect a further template argument to convert and to likewise, which you expect to be callable, that is, which you can use as in a function call:
template <typename From, typename Generator>
auto convert(From const& from, std::string& to, Generator generate)
-> decltype(
generate(std::declval<std::back_insert_iterator<std::string>&>(), from)
)
{
to.clear();
auto i = std::back_inserter(to);
return generate(i, from);
}
These kind of objects are commonly known as callable objects.
The drawback to this approach is that because c++ unfortunately does not support concepts yet, you can't do much to enforce the requirements the callable object generate should attend to. Nonetheless, this approach is what the std library successfully uses for its algorithms.
The advantage of this approach is that it can be very flexible, for any possible callable object, which minimally attends to the type requirements, can be used. That includes free functions, function objects, member functions through binding, among others. Not to mention the user is absolutely free to choose the name she wants for her callable object instead of being forced to use generate, as your initial idea would require if it were valid c++.
Now to call this modified version of convert using the free function generateyou defined, you would do that:
to<std::string>(s, generate<std::back_insert_iterator<std::string>, uint16_t>);
That isn't very nice, because since you must explicitly state the template arguments, this approach fails to take full advantage of the fact generate is a template function. Fortunately this inconvenience can be overcome by the use of function objects, like the following for instance:
struct Generator
{
template <typename Iterator, typename T>
auto operator()(Iterator& out, T i)
-> typename std::enable_if<std::is_arithmetic<T>::value, bool>::type
{
// Note: I merely use std::to_string for illustration purposes here.
auto str = std::to_string(i);
out = std::copy(str.begin(), str.end(), out);
return true;
}
};
The previous call would become simply
to<std::string>(s, Generator());
taking full advantage of its tamplate nature.
At any rate, if I got the idea correctly, this part of the code is of responsability of the user, so she, as she deserves, have full autonomy to decide which way she prefers.
I have been trying to implement in C++11 the function map from Python. It seems to work for any kind of callable objet, but I have to specify the template type parameter if I want it to work with function templates. Example:
#include <iostream>
#include <list>
template<typename T>
T abs(T x)
{
return x < 0 ? -x : x;
}
int main()
{
std::list<int> li = { -1, -2, -3, -4, -5 };
for (auto i: map(&abs<int>, li))
{
std::cout << i << std::endl;
}
}
It works fine, but I would like it to deduce the int parameter from the second argument of the function, and hence be able to write:
for (auto i: map(&abs, li))
{
std::cout << i << std::endl;
}
My map function is written as:
template<typename Callable, typename Container>
auto map(const Callable& function, Container&& iter)
-> MapObject<Callable, Container>
{
return { function, std::forward<Container>(iter) };
}
where MapObject is part of the implmentation and not a real problem here. How could I change its definition so that the template type of the Callable object can be deduced from the Container object? For example, how can map know that we have to use abs<int> for a given abs when a list<int> is given?
It works fine, but I would like it to deduce the int parameter from the second argument of the function, and hence be able to write:
for (auto i: map(&abs, li))
{
std::cout << i << std::endl;
}
The problem is that abs is not a function, but a function template, and thus there is no address-of abs, although there is &abs<int>, since abs<int> (specialization) is indeed a function (generated from a template).
Now the question is what you really want to solve, and in particular you must realize that C++ is a statically typed language where python is a dynamically typed language. It is unclear to me what you are trying to achieve here on different levels. For example, the function map in python has an equivalent in std::transform in C++:
a = [ 1, 2, 3 ]
a = map(lambda x: 2*x, a)
std::vector<int> v{1,2,3};
std::transform(v.begin(),v.end(),v.begin(),[](int x){ return 2*x; });
Where I have cheated slightly because in python it will create a different container yet in C++ transform works at the iterator level and knows of no container, but you can get the same effect similarly:
std::vector<int> v{1,2,3};
std::vector<int> result;
// optionally: result.reserve(v.size());
std::transform(v.begin(),v.end(),
std::back_inserter(result),
[](int x) { return 2*x; });
I'd advice that you learn the idioms in the language rather than trying to implement idioms from other languages...
BTW, if you are willing to have the user specify the type of the functor that is passed to the map function, then you can just pass the name of the template and let the compiler figure out what specialization you need:
template <typename Container>
auto map(Container && c,
typename Container::value_type (*f)(typename Container::value_type))
-> MapObject<Callable<T>,Container>;
template <typename T>
T abs(T value);
int main() {
std::vector<int> v{1,2,3,4};
map(v,abs);
}
This is less generic than what you were trying to do, as it only accepts function pointers and of concrete type (this is even less generic than std::transform) and it works as when the compiler sees abs (without the &) it will resolve it to the template, and thus to the set of specializations. It will then use the expected type to select one specialization and pass it in. The compiler will implicitly do &abs<int> for you in this case.
Another more generic alternative is not using functions, but functors. With this in mind you can define abs as:
struct abs {
template <typename T>
T operator()(T t) { ...}
};
And then pass a copy of the functor in instead of the function pointer. There is no need to determine the overload to be used where you pass the object abs into the map function, only when it is used. The caller side would look like:
for (auto& element : map(container,abs()))
Where the extra set of parenthesis is creating an object of type abs and passing it in.
Overall, I would try to avoid this. It is a fun thing to do, and you can probably get to a good solution, but it will be hard and require quite a bit of c++ expertise. Because it is not supported by the language, you will have to design something that works within the language and that requires compromises on different features or syntax. Knowing the options is a hard problem in itself, understanding the compromises even harder and getting to a good solution much harder. And the good solution will probably be worse than the equivalent idiomatic C++ code.
If you program in C++, program C++. Trying to code python through a C++ compiler will probably give you the pain of C++ and the performance of python.
It doesn't deduce it because you never specified that Callable is a template. You make Callable a template template parameter and it should deduce its type for you.
template<template <typename T> typename Callable, typename Container>
auto map(const Callable<T>& function, Container&& iter)
-> MapObject<Callable<T>, Container>
{
return { function, std::forward<Container>(iter) };
}
You might get bitten though as you can't take the address of a template still to be instantiated. Not sure why you need the address-of though...
I've been reviewing the draft version of the C++11 standard. Specifically the section on lambdas, and I am confused as to the reasoning for not introducing polymorphic lambdas.
For example, amongst the 100001 ways polymorphic lambdas could be used, I had hoped we could use code such as the following:
template<typename Container>
void foo(Container c)
{
for_each(c.begin(), c.end(), [](T& t) { ++t; });
}
What were the reasons:
Was it that the committee ran out of time?
That polymorphic lambdas are too hard to implement?
Or perhaps that they are seen as not being needed by the PTB?
Note: Please remember the example above is not the only one, and it is only provided as a guide to the types of code. Answers that solely concentrate on providing a workaround for the above piece of code will not be considered as valid!
Related sources:
Lambda expressions and closures for C++ (document number N1968=06-0038)
Can lambda functions be templated?
The reason we don't have polymorphic lambdas is explained pretty well in this posting.
It has to do with the concepts feature that was pulled from C++11: essentially, polymorphic lambdas are ordinary, unconstrained function templates and we didn't know how to typecheck a concept-constrained template that used an unconstrained template. However, solving that problem turns out to be easy as shown here(dead link), so I don't think there's any obstacle remaining.
The link to cpp-next is dead; the relevant info can be found here
Since the argument, c, meets the STL requirements for a container, you should be able to use something like
template<typename Container>
void foo(Container c)
{
for_each(c.begin(), c.end(),[](typename Container::reference t) { ++t; });
}
I'll also showcase John Purdy's comment above, which is another way to get the typename you want in this lambda:
template<typename Container>
void foo(Container c)
{
for_each(c.begin(),c.end(),[](decltype(*c.begin()) t) { ++t; });
}
(Yes, Dominar, I know you don't like this answer, because it doesn't answer your question, but I'm willing to bet that the next person who comes along asking this question is going to be looking for a way to make their code work, so it does make sense to have some techniques around where the question is relevant.)
It's probably because there already is a syntax for doing that, and the purpose of lambdas is to introduce a much simpler syntax that covers most cases. When you try to cover all cases (what if you wanted the auto-generated functor to inherit a particular base class?), you lose the comparative advantages (simplicity and terseness) of the lambda.
I really don't like the proposed syntax. Is T a keyword? Do all identifiers for which name lookup fails get turned automatically into template typename arguments? That prevents you from detecting misspellings, which IMO is a BAD idea:
for_each(c.begin(),c.end(),[](iterater& t) { ++t; });
// programmer misspelled "iterator" and now has a polymorphic lambda, oops
It also introduces action-at-a-distance behavior, if the named type get introduced in some header file somewhere, the meaning changes suddenly. Also really BAD.
Well, since it's supposed to create a template, we could borrow the existing syntax:
for_each(c.begin(),c.end(),[]template<typename T>(T& t) { ++t; });
This is unambiguous and now allows non-type template arguments (useful for accepting arrays by reference), but is really unwieldy. At this point you're better off writing out the functor by hand, it'll be much easier to understand.
However, I think a simple syntax is possible using the auto keyword:
for_each(c.begin(),c.end(),[](auto& t) { ++t; });
This next section incorrectly assumes that the template parameter appears on the functor type rather than its operator()():
But now you have a problem that for_each infers a typename template argument, not a template template argument. Type inference isn't possible in that context.
In the current proposal, lambdas have type, even if it's an unmentionable (other than decltype) type. You'd have to lose that feature in order to accommodate inference at the call-site.
Example showing that the issue is NOT a shortcoming of lambdas, it's simply a non-deducible context:
#include <vector>
#include <algorithm>
#include <iterator>
int main(void)
{
using namespace std;
vector<int> a(10);
vector<int> b(10);
vector<int> results;
transform(a.begin(), a.end(), b.begin(), back_inserter(results), min<int>);
}
The template type parameter to std::min must be explicitly specified. Lambdas are no different from using existing functors in this regard.
EDIT: Ok, now that I realize we aren't suggesting that the lambda generate a template functor type, but a single non-template functor type which implements a templated function application operator (operator()()), I agree that the compiler should be able to generate such a thing. I propose that using the auto keyword here would be a good simple syntax for requesting that.
However, I'm not really happy with auto either. What about lambdas with multiple parameters:
[](auto& x, auto& y){ return x + y; }
//becomes
template<typename T1, typename T2>
auto operator()(T1& x, T2& y) -> decltype(x + y) { return x + y; }
Ok, that works well enough, but what if we wanted two parameters but only one type argument:
[](auto& x, decltype(x)& y){ return x + y; }
//becomes
template<typename T1>
auto operator()(T1& x, T1& y) -> decltype(x + y) { return x + y; }
Seems ok, but I find the syntax misleading. The syntax suggests that the type parameter is inferred from the first actual parameter, and the second parameter is coerced to the same type, but actually both actual parameters are considered equal during type inference.
Perhaps it's best that this case be limited to one lambda parameter per type argument, and if you want something more constrained, write the functor yourself. This seems to me to be a good compromise between flexibility and power vs keeping the syntax simple.
Well, now that you've linked n1968, the answer to your question is apparent. It's found in section 5.1 of the proposal.
The following (your comment to my other answer above) works:
#include <algorithm>
#include <vector>
struct foo
{
template<typename T>
void operator()(T& t)
{
++t;
}
};
int main()
{
std::vector<int> v;
std::for_each(v.begin (),v.end(),foo());
return 0;
}
But the following does not:
#include <algorithm>
#include <vector>
template<typename T>
struct foo
{
void operator()(T& t)
{
++t;
}
};
int main()
{
std::vector<int> v;
std::for_each(v.begin (),v.end(),foo()); // <-- the syntax for foo here
// is kinda fictitious
return 0;
}
Probably the C++ committee saw lambdas as being more similar to the second example than the first. (Though I haven't figured out clever way to define a lambda in which this would make a difference. Anyone got any crazy ideas?)
I've been reviewing the draft version of the C++11 standard. Specifically the section on lambdas, and I am confused as to the reasoning for not introducing polymorphic lambdas.
For example, amongst the 100001 ways polymorphic lambdas could be used, I had hoped we could use code such as the following:
template<typename Container>
void foo(Container c)
{
for_each(c.begin(), c.end(), [](T& t) { ++t; });
}
What were the reasons:
Was it that the committee ran out of time?
That polymorphic lambdas are too hard to implement?
Or perhaps that they are seen as not being needed by the PTB?
Note: Please remember the example above is not the only one, and it is only provided as a guide to the types of code. Answers that solely concentrate on providing a workaround for the above piece of code will not be considered as valid!
Related sources:
Lambda expressions and closures for C++ (document number N1968=06-0038)
Can lambda functions be templated?
The reason we don't have polymorphic lambdas is explained pretty well in this posting.
It has to do with the concepts feature that was pulled from C++11: essentially, polymorphic lambdas are ordinary, unconstrained function templates and we didn't know how to typecheck a concept-constrained template that used an unconstrained template. However, solving that problem turns out to be easy as shown here(dead link), so I don't think there's any obstacle remaining.
The link to cpp-next is dead; the relevant info can be found here
Since the argument, c, meets the STL requirements for a container, you should be able to use something like
template<typename Container>
void foo(Container c)
{
for_each(c.begin(), c.end(),[](typename Container::reference t) { ++t; });
}
I'll also showcase John Purdy's comment above, which is another way to get the typename you want in this lambda:
template<typename Container>
void foo(Container c)
{
for_each(c.begin(),c.end(),[](decltype(*c.begin()) t) { ++t; });
}
(Yes, Dominar, I know you don't like this answer, because it doesn't answer your question, but I'm willing to bet that the next person who comes along asking this question is going to be looking for a way to make their code work, so it does make sense to have some techniques around where the question is relevant.)
It's probably because there already is a syntax for doing that, and the purpose of lambdas is to introduce a much simpler syntax that covers most cases. When you try to cover all cases (what if you wanted the auto-generated functor to inherit a particular base class?), you lose the comparative advantages (simplicity and terseness) of the lambda.
I really don't like the proposed syntax. Is T a keyword? Do all identifiers for which name lookup fails get turned automatically into template typename arguments? That prevents you from detecting misspellings, which IMO is a BAD idea:
for_each(c.begin(),c.end(),[](iterater& t) { ++t; });
// programmer misspelled "iterator" and now has a polymorphic lambda, oops
It also introduces action-at-a-distance behavior, if the named type get introduced in some header file somewhere, the meaning changes suddenly. Also really BAD.
Well, since it's supposed to create a template, we could borrow the existing syntax:
for_each(c.begin(),c.end(),[]template<typename T>(T& t) { ++t; });
This is unambiguous and now allows non-type template arguments (useful for accepting arrays by reference), but is really unwieldy. At this point you're better off writing out the functor by hand, it'll be much easier to understand.
However, I think a simple syntax is possible using the auto keyword:
for_each(c.begin(),c.end(),[](auto& t) { ++t; });
This next section incorrectly assumes that the template parameter appears on the functor type rather than its operator()():
But now you have a problem that for_each infers a typename template argument, not a template template argument. Type inference isn't possible in that context.
In the current proposal, lambdas have type, even if it's an unmentionable (other than decltype) type. You'd have to lose that feature in order to accommodate inference at the call-site.
Example showing that the issue is NOT a shortcoming of lambdas, it's simply a non-deducible context:
#include <vector>
#include <algorithm>
#include <iterator>
int main(void)
{
using namespace std;
vector<int> a(10);
vector<int> b(10);
vector<int> results;
transform(a.begin(), a.end(), b.begin(), back_inserter(results), min<int>);
}
The template type parameter to std::min must be explicitly specified. Lambdas are no different from using existing functors in this regard.
EDIT: Ok, now that I realize we aren't suggesting that the lambda generate a template functor type, but a single non-template functor type which implements a templated function application operator (operator()()), I agree that the compiler should be able to generate such a thing. I propose that using the auto keyword here would be a good simple syntax for requesting that.
However, I'm not really happy with auto either. What about lambdas with multiple parameters:
[](auto& x, auto& y){ return x + y; }
//becomes
template<typename T1, typename T2>
auto operator()(T1& x, T2& y) -> decltype(x + y) { return x + y; }
Ok, that works well enough, but what if we wanted two parameters but only one type argument:
[](auto& x, decltype(x)& y){ return x + y; }
//becomes
template<typename T1>
auto operator()(T1& x, T1& y) -> decltype(x + y) { return x + y; }
Seems ok, but I find the syntax misleading. The syntax suggests that the type parameter is inferred from the first actual parameter, and the second parameter is coerced to the same type, but actually both actual parameters are considered equal during type inference.
Perhaps it's best that this case be limited to one lambda parameter per type argument, and if you want something more constrained, write the functor yourself. This seems to me to be a good compromise between flexibility and power vs keeping the syntax simple.
Well, now that you've linked n1968, the answer to your question is apparent. It's found in section 5.1 of the proposal.
The following (your comment to my other answer above) works:
#include <algorithm>
#include <vector>
struct foo
{
template<typename T>
void operator()(T& t)
{
++t;
}
};
int main()
{
std::vector<int> v;
std::for_each(v.begin (),v.end(),foo());
return 0;
}
But the following does not:
#include <algorithm>
#include <vector>
template<typename T>
struct foo
{
void operator()(T& t)
{
++t;
}
};
int main()
{
std::vector<int> v;
std::for_each(v.begin (),v.end(),foo()); // <-- the syntax for foo here
// is kinda fictitious
return 0;
}
Probably the C++ committee saw lambdas as being more similar to the second example than the first. (Though I haven't figured out clever way to define a lambda in which this would make a difference. Anyone got any crazy ideas?)