C++ has an obnoxious limitation that it is impossible to pass overloaded functions to templates, for example std::max can not be nicely used with std::transform.
I was thinking that it would be nice if concepts could solve this, but in my attempts I hit the same issue. It looks like concepts are not able to constrain the template based on predicate on function type.
Example:
#include <type_traits>
#include <iostream>
#include <boost/callable_traits/args.hpp>
namespace ct = boost::callable_traits;
template <typename Fn>
concept Fn1 = std::tuple_size<ct::args_t<Fn>>::value == 1;
template <typename Fn>
concept Fn2 = std::tuple_size<ct::args_t<Fn>>::value == 2;
template<Fn1 Fn>
auto make(Fn f){
return 1;
}
template<Fn2 Fn>
auto make(Fn f){
return 2;
}
auto fn(int a){
}
auto fn(int a, float b){
return 2;
}
int main() {
std::cout << make(fn) << std::endl;
std::cout << make(fn) << std::endl;
}
notes:
I know about different solutions to this problem, this is just an example problem to ask specifically if this can be done with concepts.
I know that just dispatching on arity is primitive, e.g. predicate should also return bool, etc.
In order for the language to consider whether a type fulfills a concept, C++ must first deduce the type of the argument and plug it into the template function. That deduction cannot happen because the argument is a name representing a function with multiple overloads. So concepts don't even get a chance to work.
So long as an expression consisting of the name of an overloaded function cannot undergo template argument deduction, what you're trying to do cannot work.
And even if it did work, it still wouldn't work. In this hypothetical, fn fulfills both concepts. And while overloading based on concepts is a thing, it's a thing based on comparing the atomic constraints to look for similarities to see which is more constrained. But their atomic constraints are unrelated (as far as C++ is concerned). Thus, both would be considered equally as valid, and therefore concept overloading would fail.
You're just going to have to do what everyone else does: create a lambda.
Related
I have seen that one of the always given reasons of using trailing return types is when we want to deduce the return type from the input arguments.
I know there are other reasons but I'm focusing this specific one in this question.
One of the given example is:
template <typename T>
auto func(const T & t) -> decltype(std::cout << t)
{
return std::cout << t;
}
But I could not figure out any concrete use-case of this.
I mean, we always know the return type of a function when we write it, I can't find any concrete example when deducing the return type from arguments is really needed and cannot be avoided.
We can always (if I'm not mistaken) rewrite the function's prototype by directly specifying the return type without any deduction which makes it more concise and clearer in my sense.
The above example can be rewritten as:
template <typename T>
std::ostream& func(const T & t)
{
return std::cout << t;
}
In my opinion, this is less verbose and more readable than the trailing return type version.
What am I missing ?
I mean, we always know the return type of a function when we write it
Do we? So If you write this function template:
template<typename A, typename B>
/* ret */ foo(A a, B b) {
return a + b;
}
You can say for sure what ret is? If given two integer then it's an integer, sure. But if provided an integer and a long, it should be long due to promotions. And if one argument is a double, than the result should be a double two.
And what if that's two objects of some class types? Now we are calling an overloaded operator+, and there's absolutely no guessing what it may return.
I hope your'e convinced now that by saying we accept any two types, we cannot always be sure what is the type of an expression involving those types.
So a mechanism was added to the language to tell. Granted, this example is overly simple and is likely superseded by auto return types, but the general principle remains. When writing generic code, we often deal with unknown types. There is almost no knowing what should be the type of an expression involving them, or even if an expression like that is valid before the function is instantiated. decltype tells us that.
The above example can be rewritten as:
No it cannot. Your conclusion is based on the assumption that there is a:
std::ostream& operator<<(std::ostream&,const T&);
But this need not be the case. It could be a
any_other_type operator<<(std::ostream&,const T&);
Then your version of the method would fail to compile, while the one with deduced return type would be fine.
For a concrete use case, consider some kind of io-manipulation that lets you write code such as
std::cout << all_caps_modifier << "some text" << back_to_normal_modifier << " more text";
That would print:
SOME TEXT more text
I admit this is a rather contrived example, but using some proxy that encapsulates std::cout and makes the string getting printed in capital letters is a possible way to implement it ( std::cout << all_caps_modifier would return a type different from std::ostream&).
For example using Visual Studio 16.3 with the
/std:c++latest
flag as declared here here I can write.
#include <concepts>
template <std::integral T>
T plus1(T a) {
return a + 1;
}
int main() {
auto i = plus1(10);
}
However I can't write
#include <concepts>
std::integral plus1(std::integral a) {
return a + 1;
}
int main() {
auto i = plus1(10);
}
But I read here that this should be possible.
The Concepts TS offered what is called "terse syntax", which allows you to implicitly declare a function to be a template by using a concept instead of a typename in a parameter list. This was deemed controversial by the ISO C++ committee when attempting to incorporate Concepts TS into the standard. They wanted a way to know by looking at a function declaration whether it was a template or not.
After some back and forth, they came up with an alternate terse syntax: you use auto deduction (taken from generic lambdas), constrained by a concept name:
std::integral auto plus1(std::integral auto a) {
return a + 1;
}
However, most concepts implementations at present implement the Concepts TS functionality, with the newer stuff not yet implemented. VS never had a Concepts TS implementation, and they explicitly say that they have not yet implemented terse template syntax of this sort.
No. Only in basic cases.
In some situations you may need, for example, an exact type.
For instance, to do a forwarding call you write
template <class ... TT>
void SomeFunc(TT && ... tt)
{
AnotherFunc( std::forward<TT>(tt)... );
}
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?)
I've recently found myself using the following macro with gcc 4.5 in C++11 mode:
#define RETURN(x) -> decltype(x) { return x; }
And writing functions like this:
template <class T>
auto f(T&& x) RETURN (( g(h(std::forward<T>(x))) ))
I've been doing this to avoid the inconvenience having to effectively write the function body twice, and having keep changes in the body and the return type in sync (which in my opinion is a disaster waiting to happen).
The problem is that this technique only works on one line functions. So when I have something like this (convoluted example):
template <class T>
auto f(T&& x) -> ...
{
auto y1 = f(x);
auto y2 = h(y1, g1(x));
auto y3 = h(y1, g2(x));
if (y1) { ++y3; }
return h2(y2, y3);
}
Then I have to put something horrible in the return type.
Furthermore, whenever I update the function, I'll need to change the return type, and if I don't change it correctly, I'll get a compile error if I'm lucky, or a runtime bug in the worse case. Having to copy and paste changes to two locations and keep them in sync I feel is not good practice.
And I can't think of a situation where I'd want an implicit cast on return instead of an explicit cast.
Surely there is a way to ask the compiler to deduce this information. What is the point of the compiler keeping it a secret? I thought C++11 was designed so such duplication would not be required.
It would appear that g++ 4.8 is getting an implementation of auto return type deduction.
The patch was put in by Jason Merrill who is also sending a paper for C++-1Y for the feature. The feature is available with -std=c++1y.
Still playing with it.
The rationale for this behavior is given in the draft, 8.3.5p12:
A trailing-return-type is most useful
for a type that would be more
complicated to specify before the
declarator-id:
template <class T, class U> auto add(T t, U u) -> decltype(t + u);
rather than
template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
So this is really only meant to simplify the case where referring to the parameter names helps.
If you assume that C++ could always infer the return type of functions from the function body: this is not going to fly. It's a goal of C++ (and C) to allow modularity by separating declaration from implementation, so at the point of the call, you may not have the body of the function available. However, every caller needs to know the parameter types and the return type of every function/method being called.
If you are simply trying to set the return type, make it a template argument. This way you can change everything related to the return type without actually changing the function. You can put a default return type if you want like in this example.
template <class R = int, class T>
R f(T&& x)
{
...
return h2(y2, y3);
}
The code below demonstrates it's effectiveness.
DEMO CODE:
#include <iostream>
#include <iomanip>
template <class T, class S>
T h2(T& x, S& y)
{
return x + y;
}
template <class R = int, class T>
R f(T& x)
{
auto y2 = x;
auto y3 = x;
return h2(y2, y3);
}
int main(int argc, char** argv)
{
int x = 7;
std::string str = "test! ";
auto d = f<double>(x);
auto i = f(x); // use default type (int)
auto s = f<std::string>(str);
std::cout << std::fixed << std::setprecision(4);
std::cout << "double: " << d << std::endl;
std::cout << "int: " << i << std::endl;
std::cout << "string: " << s << std::endl;
return 0;
}
OUTPUT:
double: 14.0000
int: 14
string: test! test!
Unfortunately, the exact functionality you are looking for does not exist (yet) and is not part of the C++0x spec. However, it is possible this may be part of the C++1x spec when it is drafted. until then, stick to templates.
EDIT: oops, I just realized that there's a scoping difference between the trailing-return-type specifier and the return statement. Specifically:
auto f(int a)
{
char r[sizeof(f(a))+1];
return r;
}
Kaboom!
Previous answer:
It's unfortunate that the language does not provide a syntax to have the compiler infer the return type in this case, because it's trivial to show that inference is possible.
Specifically, we are talking about the case where there is exactly one return statement inside the function.
Independent of where in the function that return statement is, or how complex the preceding code is, it should be clear that the following transformation is possible:
return (ugly expression);
into
auto return_value = (ugly expression);
return return_value;
If the compiler can infer the type of return_value (and according to the C++0x rules, it can), then the inferred type of return_value can be chosen as the return type of the function.
It therefore seems to me that a modification to C++0x where the trailing return type specifier should only be required when the multiplicity of return statements is not exactly one would be feasible and solve the problem.
I agree with Yttrill. Return type deduction has already been proved to be a feasible practice in languages like Haskell, and since C++ has already achieved 'auto', it is just one step further to achieve return type deduction. This deduction should happens at the time of specialization, not template definition, since information of the real type supplied to the template is needed. The separate of declaration and definition is no longer a common practice in generic C++, because template body must be written in header files, and hence template bodies almost always go with template declarations. In situations where there are multiple return statements and types of them do not match, the compiler can happily report en error. In summary, return type deduction is totally possible in C++, if the committee wants to. And it's VERY important, because the duplication of manually writing return types hinders the pervasive use of small generic helper functions, which is such a common practice in functional and generic programming.
Many programming languages including Ocaml and Felix can deduce the return type of a function and do not require it to be specified. In Ocaml you can and must specify it in an interface. In Felix I have found for some functions it is wise to specify it in library code to make it easier to use.
I am surprised "auto" doesn't work for return types, it was certainly on the plate. Was this considered too hard to implement? [It isn't trivial given that a function can be recursive].
Ohhh .. now I see. The problem is the stupid template design feature "dependent names":
template<class T> auto f(T a) { return a.f(); }
So whilst it is a bit tricky to compute the return type of an ordinary function due to overloading, it is impossible with templates due to dependent name lookup: it could only be done after instantiation. But overloading must happen before that. So auto return types can't go in the language because it doesn't generalise to templates.