I'm trying to write a generic fold function using the new anonymous functions available in C++11, here is what I have:
template<typename T>
T foldl(std::function<T(T,T)> f, T initial, std::vector<T> items) {
T accum = initial;
for(typename std::vector<T>::iterator it = items.begin(); it != items.end(); ++it) {
accum = f(accum, (*it));
}
return accum;
}
The following attempt to use it:
std::vector<int> arr;
arr.assign(8, 2);
foldl([] (int x, int y) -> int { return x * y; }, 1, arr);
causes an error:
main.cpp:44:61: error: no matching function for call to 'foldl(main(int, char**)::<lambda(int, int)>, int, std::vector<int>&)'
main.cpp:44:61: note: candidate is:
main.cpp:20:3: note: template<class T> T foldl(std::function<T(T, T)>, T, std::vector<T>)
main.cpp:20:3: note: template argument deduction/substitution failed:
main.cpp:44:61: note: 'main(int, char**)::<lambda(int, int)>' is not derived from 'std::function<T(T, T)>'
It seems to me that using std::function is not the right way to go about defining the type of f. How can I correct this?
Your code is not very generic. There is no need to require a function, vector, or anything of the kind. And generally, in C++, functions would go at the end of the argument list (especially important for lambdas, as they can be big).
So it would be better (ie: more standard) to write this as this:
template<typename Range, typename Accum>
typename Range::value_type foldl(const Range &items, const typename Range::value_type &initial, Accum f)
{
typename Range::value_type accum = initial;
for(const auto &val : items) {
accum = f(accum, val);
}
return accum;
}
Or you could just use std::accumulate which does the exact same thing.
I'm not certain why this template is failing, but switching over to using a template parameter for the function instead of std::function<> seems to work wonderfully.
template<typename T, typename F>
T foldl(F f, T initial, std::vector<T> items) {
If you simply convert it to an std::function first, and then use that, it will work:
std::vector<int> arr;
arr.assign(8, 2);
std::function<int(int,int)> f = [] (int x, int y) -> int { return x * y; };
foldl(f, 1, arr);
The problem is that lambda is a different type than std::function. Each lambda is a separate type. Although a lambda (and all other function objects) is convertible to a std::function with appropriate type parameter, the compiler has no idea what template argument for T would make it convertible. (We happen to know that T = int would work, but there is no general way to figure it out.) So it cannot compile it.
Related
Have educational task: write template function, which takes arbitrary std::tuple and 2 indexes inside and returns std::pair, containing elements of given std::tuple with correspondent indexes.
Example:
auto t = std::make_tuple(0, 3.5, "Hello");
std::pair<double, char const *> p = to_pair<1,2>(t);
// p contains 3.5 and "Hello"
Written something like this:
template<int I, int J>
auto to_pair(std::tuple t) -> decltype(std::make_pair(std::get<I>(t), std::get<J>(t))) {
return std::make_pair(std::get<I>(t), std::get<J>(t));
}
However got an error:
r: missing template arguments before ‘t’
auto to_pair(std::tuple t) -> decltype(std::make_pair(get<I>t, get<J>t))
^
What I'm doing wrong and what is correct syntax here?
std::tuple is a template class, so there's no std::tuple, only std::tuple<T, ...>. In your case, the type of t is std::tuple<int, double, char const *>.
Also, you're calling std::get without an argument (there's missing braces).
You're almost there, the function should be something along the lines of:
template<int I, int J, class... T>
auto to_pair(std::tuple<T...> t)
-> decltype(std::make_pair(std::get<I>(t), std::get<J>(t))) {
return std::make_pair(std::get<I>(t), std::get<J>(t));
}
The idea is simple and straight-forward:
Keep breaking the n dimensional vector into n-1 dimensional constituent vectors, until you have access to the primitive-datatype objects. Then add them all.
The problem is, how to infer the return type?
It can be done like this, but it already assumes the datatype of summing variable (return-type):
typedef int SumType;
template <class T>
T Sum (const T x)
{
return x;
}
template <class T>
SumType Sum (const std::vector<T>& v)
{
SumType sum = 0;
for (const auto& x: v)
sum += Sum(x);
return sum;
}
But I don't want to do it like above. I feel like its against the spirit of meta-programming.
We must infer the return-type by keeping dissecting the vector into its constituent vectors until we reach the primitive-datatype objects, and then choose the return-type as the primitive-datatype.
Is it possible in C++ ? (I'm noob in meta-programming)
P.S.
std::accumulate() from <numeric> could have been helpful, but it by-passes the problem by inferring the return-type from its third argument __init.
This can be done without any template meta programming. You can let the compiler infer the type using auto and decltype:
template <class T>
T Sum(const T x) {
return x;
}
template <class T>
auto Sum(const std::vector<T> &v) {
decltype(Sum(v[0])) sum = 0;
for (const auto &x : v)
sum += Sum(x);
return sum;
}
The return type of Sum is automatically deduced from sum and the type of sum is whatever Sum(v[0]) returns. Eventually you will end up with the first version of Sum which returns T and the compiler knows that type.
Demo
What we can do is use T.C.'s data_type class to get the the underlying type. That is defined as
template<class T> struct voider { typedef void type; };
template<class T, class = void>
struct data_type {
typedef T type;
};
template<class T>
struct data_type<T, typename voider<typename T::value_type>::type>
: data_type<typename T::value_type> {};
Using that we can modify the primary Sum to
template <class T, class Ret = typename data_type<std::vector<T>>::type>
Ret Sum (const std::vector<T>& v)
{
Ret sum = 0;
for (const auto& x: v)
sum += Sum(x);
return sum;
}
So then you can use something like
int main()
{
std::cout << Sum(std::vector<std::vector<std::vector<int>>>{{{1},{2},{3}},{{4},{5},{6}}});
}
which outputs
21
Live Example
You've almost figured out the answer for yourself. Pay attention to this line:
sum += Sum(x);
The type of sum, which is what we’re after, must be something compatible for assignment with the result of our recursive call to Sum. One such type, given your requirements, is certainly the result type of the call.
We don't have to rely on just a fuzzy feeling though. Meta-programming is, after all, programming. You may not have realised it, but your problem is one of well-founded recursion which means that the principle of induction can guide us towards an answer.
in the base case, we have a numerical, non-vector element_type element;, meaning our result type is… element_type. you've in fact already managed this step, it’s the first overload:
template<typename T>
T Sum(T element);
in the recursive case we have:
std::vector<element_type> vec;
the induction hypothesis, i.e.:
// given
element_type element;
// we know the following is well-formed and a numerical type
using recursive_result_type = decltype( Sum(element) );
Since the vector elements have type element_type, the induction hypothesis gives us that the result of calling Sum on them has all the properties we want. (The justification for our += intuition is rooted here.) We have our anser: we use recursive_result_type as-is.
Now as it turns out that second overload cannot just be written e.g. like so:
// doesn't behave as expected
template<typename Element>
auto Sum(std::vector<Element> const& vec) -> decltype( Sum(vec.front()) );
The reason being that the current Sum overload being declared is not in scope in the return type (even though it is in the definition body). One way to work around that is to rely on class scope, which is more accommodating:
// defining a functor type with operator() overloads
// would work just as well
struct SumImpl {
template<typename Element>
static T apply(Element element)
{ return element; }
template<typename Element>
static auto apply(std::vector<Element> const& vec)
-> decltype( apply(vec.front()) )
{
using result_type = decltype( apply(vec.front()) );
result_type sum = 0;
for(auto const& element: vec) {
sum += apply(element);
}
return sum;
}
};
template<typename Arg>
using sum_result_t = decltype( SumImpl::apply(std::declval<Arg const&>()) );
template<typename Arg>
sum_result_t<Arg> Sum(Arg const& arg)
{ return SumImpl::apply(arg); }
Coliru demo
I'm learning C++, and I'm trying to implement a binary search function that finds the first element for which a predicate holds. The function's first argument is a vector and the second argument is a function that evaluates the predicate for a given element. The binary search function looks like this:
template <typename T> int binsearch(const std::vector<T> &ts, bool (*predicate)(T)) {
...
}
This works as expected if used like this:
bool gte(int x) {
return x >= 5;
}
int main(int argc, char** argv) {
std::vector<int> a = {1, 2, 3};
binsearch(a, gte);
return 0;
}
But if I use a lambda function as a predicate, I get a compiler error:
search-for-a-range.cpp:20:5: error: no matching function for call to 'binsearch'
binsearch(a, [](int e) -> bool { return e >= 5; });
^~~~~~~~~
search-for-a-range.cpp:6:27: note: candidate template ignored: could not match 'bool (*)(T)' against '(lambda at
search-for-a-range.cpp:20:18)'
template <typename T> int binsearch(const std::vector<T> &ts,
^
1 error generated.
The above error is generated by
binsearch(a, [](int e) -> bool { return e >= 5; });
What's wrong? Why is the compiler not convinced that my lambda has the right type?
Your function binsearch takes a function pointer as argument. A lambda and a function pointer are different types: a lambda may be considered as an instance of a struct implementing operator().
Note that stateless lambdas (lambdas that don't capture any variable) are implicitly convertible to function pointer. Here the implicit conversion doesn't work because of template substitution:
#include <iostream>
template <typename T>
void call_predicate(const T& v, void (*predicate)(T)) {
std::cout << "template" << std::endl;
predicate(v);
}
void call_predicate(const int& v, void (*predicate)(int)) {
std::cout << "overload" << std::endl;
predicate(v);
}
void foo(double v) {
std::cout << v << std::endl;
}
int main() {
// compiles and calls template function
call_predicate(42.0, foo);
// compiles and calls overload with implicit conversion
call_predicate(42, [](int v){std::cout << v << std::endl;});
// doesn't compile because template substitution fails
//call_predicate(42.0, [](double v){std::cout << v << std::endl;});
// compiles and calls template function through explicit instantiation
call_predicate<double>(42.0, [](double v){std::cout << v << std::endl;});
}
You should make your function binsearch more generic, something like:
template <typename T, typename Predicate>
T binsearch(const std::vector<T> &ts, Predicate p) {
// usage
for(auto& t : ts)
{
if(p(t)) return t;
}
// default value if p always returned false
return T{};
}
Take inspiration from standard algorithms library.
The lambda expression with empty capture list could be implicitly converted to a function pointer. But the function pointer predicate is taking T as its parameter, that need to be deduced. Type conversion won't be considered in template type deduction, T can't be deduced; just as the error message said, candidate template (i.e. binsearch) is ignored.
You can use operator+ to achieve this, it'll convert lambda to function pointer, which will be passed to binsearch later and then T will be successfully deduced[1].
binsearch(a, +[](int e) -> bool { return e >= 5; });
// ~
Of course you could use static_cast explicitly:
binsearch(a, static_cast<bool(*)(int)>([](int e) -> bool { return e >= 5; }));
Note if you change predicate's type to be independent of T, i.e. bool (*predicate)(int), passing lambda with empty capture list would work too; the lambda expression will be converted to function pointer implicitly.
Another solution is changing the parameter type from function pointer to std::function, which is more general for functors:
template <typename T> int binsearch(const std::vector<T> &ts, std::function<bool (typename std::vector<T>::value_type)> predicate) {
...
}
then
binsearch(a, [](int e) -> bool { return e >= 5; });
[1] A positive lambda: '+[]{}' - What sorcery is this?
Why is the compiler not convinced that my lambda has the right type?
Template functions being told to deduce their template parameters do no conversion. A lambda is not a function pointer, so there is no way to deduce the T in that argument. As all function arguments independently deduce their template parameters (unless deduction is blocked), this results in an error.
There are a number of fixes you can do.
You can fix the template function.
template <class T>
int binsearch(const std::vector<T> &ts, bool (*predicate)(T))
Replace the function pointer with a Predicate predicate or Predicate&& predicate and leave the body unchanged.
template <class T, class Predicate>
int binsearch(const std::vector<T> &ts, Predicate&& predicate)
Use deduction blocking:
template<class T>struct tag_t{using type=T;};
template<class T>using block_deduction=typename tag_t<T>::type;
template <class T>
int binsearch(const std::vector<T> &ts, block_deduction<bool (*)(T)> predicate)
optionally while replacing the function pointer with a std::function<bool(T)>.
You can fix it at the call site.
You can pass T manually binsearch<T>(vec, [](int x){return x<0;}).
You can decay the lambda to a function pointer with putting a + in front of it +[](int x) ... or a static_cast<bool(*)(int)>( ... ).
The best option is Predicate one. This is also what standard library code does.
We can also go a step further and make your code even more generic:
template <class Range, class Predicate>
auto binsearch(const Range &ts, Predicate&& predicate)
-> typename std::decay< decltype(*std::begin(ts)) >::type
The -> typename std::decay ... trailing return type part can be eliminated in C++14.
A benefit to this is that if the body also uses std::begin and std::end to find begin/end iterators, binsearch now supports deques, flat C-style arrays, std::arrays, std::strings, std::vectors, and even some custom types.
If you have any control over binsearch I suggest you refactor it:
template <typename T, typename Predicate>
int binsearch(std::vector<T> const& vec, Predicate&& pred) {
// This is just to illustrate how to call pred
for (auto const& el : vec) {
if (pred(el)) {
// Do something
}
}
return 0; // Or anything meaningful
}
Another way for you is to perform type-erasure on your functor objects/function pointers/whatever... by embedding them into an std::function<bool(T const&)>. To do so, just rewrite the function above as:
template <typename T>
int binsearch(std::vector<T> const& vec, std::function<bool(T const&)> pred);
But since template argument deduction does not do any conversion, you need to explicitly feed your function like the following:
auto my_predicate = [](int x) { return true; }; // Replace with actual predicate
std::vector<int> my_vector = {1, 2, 3, 4};
binsearch(my_vector, std::function<bool (int const&)>(my_predicate));
However given the description of your function, it seems it does the same job as std::find_if.
std::vector<int> my_vector = {1, 12, 15, 13, 16};
auto it = std::find_if(std::begin(my_vector), std::end(my_vector),
[](int vec_el) { return !vec_el%5; });
// it holds the first element in my_vector that is a multiple of 5.
if (it != std::end(my_vector)) {
std::cout << *it << std::endl; // prints 15 in this case
}
Note that to do a binary search, you need more than just a predicate: you need a predicate that defines an order on your range AND a target value.
A function pointer and a lambda function is not the same thing.
An object t can not be assigned to predicate where:
bool (*predicate)(int)
and
auto t = [](int e) -> bool { return e >= 5; });
Might as well use std::function<bool(int)>. Your signature will look like this:
template <typename T>
int binsearch(const std::vector<T> &ts, std::function<bool(T)> predicate){
// ...
}
Now that's not a function pointer, You'll need to bind your founction pointers if they are necessary, (I assume you're fine with just lambdas)
I'm learning C++, and I'm trying to implement a binary search function that finds the first element for which a predicate holds. The function's first argument is a vector and the second argument is a function that evaluates the predicate for a given element. The binary search function looks like this:
template <typename T> int binsearch(const std::vector<T> &ts, bool (*predicate)(T)) {
...
}
This works as expected if used like this:
bool gte(int x) {
return x >= 5;
}
int main(int argc, char** argv) {
std::vector<int> a = {1, 2, 3};
binsearch(a, gte);
return 0;
}
But if I use a lambda function as a predicate, I get a compiler error:
search-for-a-range.cpp:20:5: error: no matching function for call to 'binsearch'
binsearch(a, [](int e) -> bool { return e >= 5; });
^~~~~~~~~
search-for-a-range.cpp:6:27: note: candidate template ignored: could not match 'bool (*)(T)' against '(lambda at
search-for-a-range.cpp:20:18)'
template <typename T> int binsearch(const std::vector<T> &ts,
^
1 error generated.
The above error is generated by
binsearch(a, [](int e) -> bool { return e >= 5; });
What's wrong? Why is the compiler not convinced that my lambda has the right type?
Your function binsearch takes a function pointer as argument. A lambda and a function pointer are different types: a lambda may be considered as an instance of a struct implementing operator().
Note that stateless lambdas (lambdas that don't capture any variable) are implicitly convertible to function pointer. Here the implicit conversion doesn't work because of template substitution:
#include <iostream>
template <typename T>
void call_predicate(const T& v, void (*predicate)(T)) {
std::cout << "template" << std::endl;
predicate(v);
}
void call_predicate(const int& v, void (*predicate)(int)) {
std::cout << "overload" << std::endl;
predicate(v);
}
void foo(double v) {
std::cout << v << std::endl;
}
int main() {
// compiles and calls template function
call_predicate(42.0, foo);
// compiles and calls overload with implicit conversion
call_predicate(42, [](int v){std::cout << v << std::endl;});
// doesn't compile because template substitution fails
//call_predicate(42.0, [](double v){std::cout << v << std::endl;});
// compiles and calls template function through explicit instantiation
call_predicate<double>(42.0, [](double v){std::cout << v << std::endl;});
}
You should make your function binsearch more generic, something like:
template <typename T, typename Predicate>
T binsearch(const std::vector<T> &ts, Predicate p) {
// usage
for(auto& t : ts)
{
if(p(t)) return t;
}
// default value if p always returned false
return T{};
}
Take inspiration from standard algorithms library.
The lambda expression with empty capture list could be implicitly converted to a function pointer. But the function pointer predicate is taking T as its parameter, that need to be deduced. Type conversion won't be considered in template type deduction, T can't be deduced; just as the error message said, candidate template (i.e. binsearch) is ignored.
You can use operator+ to achieve this, it'll convert lambda to function pointer, which will be passed to binsearch later and then T will be successfully deduced[1].
binsearch(a, +[](int e) -> bool { return e >= 5; });
// ~
Of course you could use static_cast explicitly:
binsearch(a, static_cast<bool(*)(int)>([](int e) -> bool { return e >= 5; }));
Note if you change predicate's type to be independent of T, i.e. bool (*predicate)(int), passing lambda with empty capture list would work too; the lambda expression will be converted to function pointer implicitly.
Another solution is changing the parameter type from function pointer to std::function, which is more general for functors:
template <typename T> int binsearch(const std::vector<T> &ts, std::function<bool (typename std::vector<T>::value_type)> predicate) {
...
}
then
binsearch(a, [](int e) -> bool { return e >= 5; });
[1] A positive lambda: '+[]{}' - What sorcery is this?
Why is the compiler not convinced that my lambda has the right type?
Template functions being told to deduce their template parameters do no conversion. A lambda is not a function pointer, so there is no way to deduce the T in that argument. As all function arguments independently deduce their template parameters (unless deduction is blocked), this results in an error.
There are a number of fixes you can do.
You can fix the template function.
template <class T>
int binsearch(const std::vector<T> &ts, bool (*predicate)(T))
Replace the function pointer with a Predicate predicate or Predicate&& predicate and leave the body unchanged.
template <class T, class Predicate>
int binsearch(const std::vector<T> &ts, Predicate&& predicate)
Use deduction blocking:
template<class T>struct tag_t{using type=T;};
template<class T>using block_deduction=typename tag_t<T>::type;
template <class T>
int binsearch(const std::vector<T> &ts, block_deduction<bool (*)(T)> predicate)
optionally while replacing the function pointer with a std::function<bool(T)>.
You can fix it at the call site.
You can pass T manually binsearch<T>(vec, [](int x){return x<0;}).
You can decay the lambda to a function pointer with putting a + in front of it +[](int x) ... or a static_cast<bool(*)(int)>( ... ).
The best option is Predicate one. This is also what standard library code does.
We can also go a step further and make your code even more generic:
template <class Range, class Predicate>
auto binsearch(const Range &ts, Predicate&& predicate)
-> typename std::decay< decltype(*std::begin(ts)) >::type
The -> typename std::decay ... trailing return type part can be eliminated in C++14.
A benefit to this is that if the body also uses std::begin and std::end to find begin/end iterators, binsearch now supports deques, flat C-style arrays, std::arrays, std::strings, std::vectors, and even some custom types.
If you have any control over binsearch I suggest you refactor it:
template <typename T, typename Predicate>
int binsearch(std::vector<T> const& vec, Predicate&& pred) {
// This is just to illustrate how to call pred
for (auto const& el : vec) {
if (pred(el)) {
// Do something
}
}
return 0; // Or anything meaningful
}
Another way for you is to perform type-erasure on your functor objects/function pointers/whatever... by embedding them into an std::function<bool(T const&)>. To do so, just rewrite the function above as:
template <typename T>
int binsearch(std::vector<T> const& vec, std::function<bool(T const&)> pred);
But since template argument deduction does not do any conversion, you need to explicitly feed your function like the following:
auto my_predicate = [](int x) { return true; }; // Replace with actual predicate
std::vector<int> my_vector = {1, 2, 3, 4};
binsearch(my_vector, std::function<bool (int const&)>(my_predicate));
However given the description of your function, it seems it does the same job as std::find_if.
std::vector<int> my_vector = {1, 12, 15, 13, 16};
auto it = std::find_if(std::begin(my_vector), std::end(my_vector),
[](int vec_el) { return !vec_el%5; });
// it holds the first element in my_vector that is a multiple of 5.
if (it != std::end(my_vector)) {
std::cout << *it << std::endl; // prints 15 in this case
}
Note that to do a binary search, you need more than just a predicate: you need a predicate that defines an order on your range AND a target value.
A function pointer and a lambda function is not the same thing.
An object t can not be assigned to predicate where:
bool (*predicate)(int)
and
auto t = [](int e) -> bool { return e >= 5; });
Might as well use std::function<bool(int)>. Your signature will look like this:
template <typename T>
int binsearch(const std::vector<T> &ts, std::function<bool(T)> predicate){
// ...
}
Now that's not a function pointer, You'll need to bind your founction pointers if they are necessary, (I assume you're fine with just lambdas)
Why is it that optional parameters with template functions don't work in C++?
(Clarification: I'm hoping to understand why C++ was designed such that this wouldn't be possible.)
#include <iostream>
template<class T1, class T2> T1 inc(T1 v, T2 u = 1) { return v + u; }
int main() { std::cout << inc(5); }
prog.cpp: In function ‘int main()’: error: no matching function for call to ‘inc(int)’
You got it the wrong way round. Default arguments don't participate in argument deduction:
Argument deduction happens first, as part of selecting the desired overload, and then the default arguments of that overload are filled in if necessary.
What Kerrek SB said is correct, the compiler just doesn't have enough to deduce T2 from (by what it's allowed to do from the standard).
In this particular case you can probably fix it by using only one template argument for everything, i.e.
template< class T > T inc( const T v, const T u = 1 ) { return v + u; }
Default arguments do not participate in the deduction process (only to overload resolution, and the rules are very difficult to remember -- always keep it simple).
To achieve what you want, you can provide an additional overload:
template <class T1, class T2> T1 inc(T1 v, T2 u) { return v + u; }
template <class T> T inc(T v) { return v + T(1); }
Template functions in C++ are generated at compile time, and are only generated if they are needed. So you could get a function generated like:
inc( int, int );
Which would be the T1 = int and T2 = int version. The compiler can implicitly determine the type if you pass in parameters for every template argument, so:
int a = 1;
int b = 2;
inc( a, b );
The compiler could generate a function like the one above at compile time, because it can infer that T1 = int and T2 = int. If however you do what you are doing:
inc( 5 );
The compiler can determine that T1 = int, but it cannot determine what T2 is. So no function is generated, and you get the error about the function not existing. This may be fixable if you use one template parameter:
template<class T> T inc(T v, T u = 1) { return v + u; }
Or if you provide an overload:
template<class T> T inc(T v) { return v + 1; }
There is also a third way:
inc<int, int>( 5 );
But I guess this isn't what you want...