Freesteel Blog » Template members

Template members

Thursday, August 14th, 2008 at 5:40 pm Written by:

Here’s a bit of easy C++ code using a template class with a template member function that compiles and executes with no problems on MS VC8:

#include <iostream>
#include <vector>
using namespace std;

template<class T>
struct A
{
 T x;

 template
 void fun(IT& it1, IT& it2)
 {
  for(IT i = it1; i != it2; ++i)
   cout << (*i + x) << endl;
 }
};

int main(int argc, char* argv[])
{
 A<int> a;
 a.x = 1;

 vector<int> b;
 b.push_back(10);

 a.fun(b.begin(), b.end());
 return 0;
}

But try this on a linux machine with gcc (I used “gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)”) and you will get into compilation trouble:

g++ main.cpp -o main
main.cpp: In function âint main(int, char**)â:
main.cpp:27: error: no matching function for call to A<int>::fun(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >)
main.cpp:12: note: candidates are: void A<T>::fun(IT&, IT&) [with IT = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, T = int]
make: *** [main] Error 1

So, what’s wrong?
If there’s only one candidate, why does the compiler not instatiate that one? Why is there a matching problem, and why does VC8 not spot this?

I could wait until tomorrow with telling you the solution, but I won’t let you racking your brains…

here it is:

replace the declaration of the template member in template struct A with this:

void fun(const IT& it1, const IT& it2)

and you get a result. But why is that? You tell me!
And what do you do if you want to code a member that needs pointers, not constant references? Somebody out there who knows the answer?

3 Comments

  • 1. Clive replies at 10th September 2008, 11:07 pm :

    Are the iterators from begin() and end() const, so unable to be passed to a function expecting non-const references?
    Suspect MSVC is being slack about what it allows, and gcc is being correct.
    I could ask people who know properly rather than my rather hazy memory if you wanted.

  • 2. Martin replies at 11th September 2008, 9:41 am :

    iterators begin() and end() are overloaded:

    For the vector class you’ve got:


    iterator begin();
    const_iterator begin() const;

    so that can’t be it.

  • 3. Clive replies at 12th September 2008, 6:05 pm :

    Scratches head more. It’s a while since I’ve done any of this!

    How about:

    begin() and end() return temporaries, ie not lvalues. You can’t take a non-const reference to an lvalue, but you can take a const one. In the case of the const one, the compiler handles the temporary object’s lifetime for you.

    It’s nothing to do with the template stuff – here’s the same thing done with ints:

    #include

    int fred( int a )
    {
    return a + 1;
    }

    void jim( int&a )
    {
    std::cout << a << std::endl;
    }

    int main(int argc, char* argv[])
    {
    int x = fred( 3 );
    jim( x );
    jim( fred ( 4 ) );
    return 0;
    }

    The first jim works, the second won’t compile.
    Change jim to take const int& or int, and it’ll work fine.

    Ie MSVC is being a bit overly generous in what it’s allowing.

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <blockquote cite=""> <code> <em> <strong>