views:

352

answers:

4

My disclaimer here is that I started teaching myself C++ about a week ago and my former experience with programming has been with dynamic languages (Python, javascript).

I'm trying to iterate though the contents of a vector using a generic function to print out the items:

#include <iostream>
#include <algorithm>
#include <vector>

using std::vector;
using std::cout;

template <class T>
void p(T x){
    cout << x;
}

int main () {

    vector<int> myV;

    for(int i = 0; i < 10; i++){
        myV.push_back(i);
    }

    vector<int>::const_iterator iter = myV.begin();

    for_each(iter, myV.end(), p);

    return 0;
}

The code doesn't compile. Would someone explain why?

Edit: The compiler error:

error: no matching function for call to 'for_each(_gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<const int, _gnu_norm::vector<int, std::allocator<int> > >, __gnu_debug_def::vector<int, std::allocator<int> > >&, __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<int, __gnu_norm::vector<int, std::allocator<int> > >, __gnu_debug_def::vector<int, std::allocator<int> > >, <unknown type>)'

Thanks!

+12  A: 

Try:

for_each(myV.begin(), myV.end(), p<int>);

There were two mistakes in your code:

  • The iterators were not the same type
  • The function pointer was not actually a pointer.
    • Normally templated functions can be deduced from there parameters. But in this case you are not actually using it you are passing it (or its address) to a function (thus the normal rules on template function deduction did not work). As the compiler can not deduce which version of the function 'p' you need to use you must be explicit.

There is also a nice output iterator that does this:

std::copy(myV.begin(),myV.end(), std::ostream_iterator<int>(std::cout));

Also note that very few compilers can optimise code across a function pointer call.
Though most are able to optimise the call if it is an functor object. Thus the following may have been a viable alternative to a function pointer:

template<typename T>
struct P
{
    void operator()(T const& value) const
    {
        std::cout << value;
    }
};

....

for_each(myV.begin(), myV.end(), P<int>());

Another note:
When you use templated methods/functions it is usually better to pass by const reference than value. If the Type is expensive to copy then passing by value will generate a copy construction which may not be what you expected.

Martin York
Might add that p<int> denotes a specific function, which the compiler can produce code for. Just writing p doesn't say which type T is (int, float or rhubarb_pie?), and the c++ type-system doesn't infer that much (loosely formulated, it tends to go top-down, not bottom up).
Marcus Lindblom
Read Marcus's comment above for why :-)
Martin York
I would also be possible to have `struct P { template <class T> void oeprator()(const T } };` coupled with `for_each(myV.begin(), myV.end(), P());`. Would it be more or less efficient ?
Matthieu M.
@Martin: there's a typo in your code > you should use an upper case P in the for_each to invoke your struct. (delete when edited if you wish to avoid cluttering)
Matthieu M.
@Matthieu: Haveing the class or method templated, which is more effecient. I have no idea. I suspect it would not make much difference but this is an area for profiling. I would say it is 6 of one half a dozen of the other.
Martin York
A: 

I haven't used for_each in C++, but I would write same cycle so:

vector<int>::iterator iter;

for(iter = myV.begin(); iter != myV.end(); iter++) {
    p(iter);
}
giolekva
prefer prefix increment: ++iter
Martin York
What's the difference, I think in this situation it's matter of programmer's coding style.
giolekva
Postfix increment makes a copy, which can cause performance issues.
Fred Larson
@giolekva: Typical post-increment implementation: `T operator++(int) {T result(*this); operator++(); return result;}` That's up to three copies. If this is built-ins, the compiler will optimize them away. If it is an iterator into a linked list, I wouldn't want to bet my job on it.
sbi
In this situation there is no difference (as long as you assume the code will never be modified). It is just a habbit that you should get into so that when it does matter the problem will not affect your code. Most refactoring happens at the type level leaving the algorithm unchanged (thus an algorithm that is OK with the current types may suddenly become burdensome when the underlying container type is changed). Thus prefer the prefix version.
Martin York
+3  A: 

The reason that Martin's solution works and yours doesn't is that p is a function template, and not an actual function. A template function doesn't have an address that you can take, or pass to a function. You have to instantiate a template function, to create an actual function you can use.

cdiggins
I think it has more to do with the compiler not being abel to deduce the type of P (because it is template). You can manually instanciate multiple versions of p. But there is not enough context here for the compiler to determine which version of p to use. If you call 'p' compiler would have deduced the type and thus the address based on the parameters. ie p(5); is a valid call.
Martin York
Function templates do not have a type. They simply don't exist until instantiated. In the same way class templates aren't types, but the instantiations are.
cdiggins
Correct. Each version of the function is unique. But the compiler tries to deduce what function to call even though there are multiple versions, but in this context there is not enough information to determin which instancuation to use.
Martin York
@Martin: In the context of calling `std::for_Each`, there is no function call so there's nothing for the compiler to deduce.
sbi
@Martin: You are still incorrect. There are no functions instantiated from the template in the original poster's code.
cdiggins
@sbi: Exactly. :-)
Martin York
@cdiggins: So. The compiler will instanciate template functions as required. If it could deduce which one it needed it would automatically instanciate one and use its address. But because it cant work out which one to use it does not. No need to put the cart before the horse.
Martin York
@Martin, can you provide a concrete example of when the compiler will instantiate template functions automatically?
cdiggins
@cdiggins: `template<class T> void f(T); f(42);`
sbi
Yeah that makes perfect sense, I was stuck thinking only about function pointers, but of course the compiler deduces function from templates when they are actually called. So my reaonsing here was all a little bit wonky.
cdiggins
+1  A: 

You problem is that you have to pass some "callable entity" to std::for_each. That could be a function object (that's a class overloading the function call operator) or a function pointer. (Wherever a function pointer is needed you can pass in the name of a function with a matching prototype - functions names implicitly convert into function addresses.)

However, your p isn't a function, it's a function template. And a function template is just that: a template to create functions from. You need to pass such a created function instead of the template's name. The mechanism to let the compiler create a function from a function template is often called template instantiation. So you need an instance of the template. That is created by the compiler implicitly whenever you use such an instance.

So, as others have already said, you need to explicitly pass p<int> to std::foreach:

std::for_each(myV.begin(), myV.end(), p<int>);
sbi