I'm trying to use an ANSI C++ for_each statement to iterate over and print the elements of a standard vector. It works if I have the for_each call a non-overloaded function, but yields a compiler error if I have it call an overloaded function.
Here's a minimal test program to show where the compiler error occurs:
#include <algorithm>
#include <iostream>
#include <vector>
struct S {
char c;
int i;
};
std::vector<S> v;
void print_struct(int idx);
void print_struct(const struct S& s);
// f: a non-overloaded version of the preceding function.
void f(const struct S& s);
int main()
{
v.push_back((struct S){'a', 1});
v.push_back((struct S){'b', 2});
v.push_back((struct S){'c', 3});
for (unsigned int i = 0; i < v.size(); ++i)
print_struct(i);
/* ERROR! */
std::for_each(v.begin(), v.end(), print_struct);
/* WORKAROUND: */
std::for_each(v.begin(), v.end(), f);
return 0;
}
// print_struct: Print a struct by its index in vector v.
void print_struct(int idx)
{
std::cout << v[idx].c << ',' << v[idx].i << '\n';
}
// print_struct: Print a struct by reference.
void print_struct(const struct S& s)
{
std::cout << s.c << ',' << s.i << '\n';
}
// f: a non-overloaded version of the preceding function.
void f(const struct S& s)
{
std::cout << s.c << ',' << s.i << '\n';
}
I compiled this in openSUSE 12.2 using:
g++-4.7 -ansi -Wall for_each.cpp -o for_each
The full error message is:
for_each.cpp: In function ‘int main()’:
for_each.cpp:31:48: error: no matching function for call to ‘for_each(std::vector<S>::iterator, std::vector<S>::iterator, <unresolved overloaded function type>)’
for_each.cpp:31:48: note: candidate is:
In file included from /usr/include/c++/4.7/algorithm:63:0,
from for_each.cpp:5:
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template<class _IIter, class _Funct> _Funct std::for_each(_IIter, _IIter, _Funct)
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template argument deduction/substitution failed:
for_each.cpp:31:48: note: couldn't deduce template parameter ‘_Funct’
I don't see any search results for this particular error on Stack Overflow, or on the web generally. Any help would be appreciated.
A names refers to an overload set. You'll need to specify which overload you want:
std::for_each(v.begin(), v.end(), (void (&)(S const&)) print_struct);
Another approach is to use a polymorphic callable function object as a helper:
struct PrintStruct
{
template <typename T> void operator()(T const& v) const
{ return print_struct(v); }
};
int main()
{
PrintStruct helper;
std::vector<S> sv;
std::vector<int> iv;
// helper works for both:
std::for_each(sv.begin(), sv.end(), helper);
std::for_each(iv.begin(), iv.end(), helper);
std::for_each
declaration looks like this:
template<class InputIter, class Func>
void for_each(InputIter first, InputIter last, Func func);
As you can see, it takes anything you give it as the third parameter. There is no restriction that it has to be a callable type of a certain signature or a callable type at all.
When dealing with overloaded functions, they're inherently ambiguous unless you give them some context to select the right one. In a call to an overloaded function, this context are the arguments you pass. When you need a pointer, however, you can't use arguments as a context, and the for_each
parameter also doesn't count as a context, since it takes anything.
As an example of where a function parameter can be a valid context to select the right overload, see this:
// our overloads
void f(int){}
void f(double){}
typedef void (*funcptr_type)(int);
void g(funcptr_type){}
// ...
g(&f); // will select 'void f(int)' overload, since that's
// the only valid one given 'g's parameter
As you can see, you give a clear context here that helps the compiler select the right overload and not have it ambiguous. std::for_each
's parameters do not give such a context, since they take anything.
There are two solutions:
f
)Note that in C++11, you could also use a lambda for the second option:
std::for_each(v.begin(), v.end(), [](const S& s){ print_struct(s); });
Some notes on your code:
(struct S){'a', 1}
is a compound literal and not standard C++struct S
in C++, only S
sufficesIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With