Freesteel Blog » Template members
Template members
Thursday, August 14th, 2008 at 5:40 pm
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:
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:
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