C++ Template Issues

Started by
6 comments, last by chaospilot 17 years, 1 month ago
I'm having template issues. I have a Profile class which stores ordered pairs of double (time) and T (Matrix/double/int/bool/Quaternion/etc). I have a host of other functions that are working, but the following two (and slight variations on these two) arent working. I get a "error C2660: 'std::list<_Ty>::sort' : function does not take 1 arguments" when I try and call the function pmin, and the same with merge when I try to call it. HOWEVER, I don't get any errors when I dont try and call the functions. What gives? Code as follows. template <typename T> class Profile { private: list<pair<double, T>> data; public: friend const T pmin(const Profile<typename T>& profIn) { Profile<T> temp = profIn; temp.data.sort(profValLesser); return temp.data.front().second; } friend const Profile<T> mergeProfiles(const Profile<typename T>& prof1, const Profile<typename T>& prof2) { Profile<T> newProf; newProf.data.merge(prof1.data, profTimeLesser); newProf.data.merge(prof2.data, profTimeLesser); return newProf; } }
Advertisement
Right, forgot to throw these down:

/* used to sort Profiles pairs by time */
template<typename T> bool profTimeLesser(pair<double, T> elem1, pair<double, T> elem2) {
return elem1.first < elem2.first; }

/* used to sort Profiles pairs by value */
template<typename T> bool profValLesser(pair<double, T> elem1, pair<double, T> elem2) {
return elem1.second < elem2.second; }
list<pair<double, T>> data;

Put a space between the two '>'s:
list<pair <double, T> > data;

C++ interprates >> as a right bit-shift operator,
reguardless of its synthax use.
Fixed that and it still doesnt work... I've actually done this everywhere and it works okay on MSVS 2005.To clarify I have the following things tested and they work fine:

void addData(const pair<double, T>& pairIn) {
data.push_back(pairIn);}

void addData(const double tIn, const T& valIn) {
data.push_back(make_pair(tIn, valIn));}

const T getLastValue(void) {
_ASSERTE(data.size()>0);
if(data.size()>0)
return data.back().second;
else return data.front().second;}

const size_t size(void) {
return size(data); }

const pair<double, T> operator()(const size_t i) {
_ASSERTE(i<=data.size() && i>=1);
if(i<=data.size() && i>=1)
{
size_t add;
list<pair<double, T>>::iterator lIt = data.begin();
for(add=1; add<i; add++)
lIt++;
return *lIt;
}
else
return make_pair(0,0);}

const Profile operator=(const Profile& other) {
this->data = other.data;
return *this;}

friend const Profile operator-(Profile &A) {
list<pair<double, T>>::iterator lIt = A.data.begin();
for(lIt; lIt != A.data.end(); lIt++)
(*lIt).second = -(*lIt).second;
return A;}

friend const Profile operator-(const Profile &A, const Profile &B) {
return (A + (-B));}


friend const bool operator==(const Profile &A, const Profile &B) {
list<pair<double, T>>::const_iterator aIt = A.data.begin();
list<pair<double, T>>::const_iterator bIt = B.data.begin();
for(aIt; aIt != A.data.end(); aIt++) {
if(*aIt != *bIt)
return false;
bIt++;
}
return true;}
Besides the missing semicolen at the end of your class ( I assume its
a typo in the post) your code compilies fine for me. (MSVC++ 2005)
First, Crypter is right about the >>s. The compiler should interpret this as operator>>. However, MSVC++ 8.0 has an option that changes this behavior, and you obviously have it turned on, else that code wouldn't compile at all.

Second, you only get the error when actually calling the function because template functions are not compiled if they aren't actually called.

Finally, I believe the actual error within pmin function is that the compiler is unable to resolve the type of the argument you give it, gives up, and selects the non-template overload instead. Try explicitly specifying the template argument, such that the call becomes "temp.data.sort(profValLesser<T>);". profValLesser is a template; profValLesser<T> is a predicate. (Change the other function that does not work in the same way.)
Just a quick comment on style:

Quote:Original post by chaospilot
friend const T pmin(const Profile<typename T>& profIn) {Profile<T> temp = profIn;temp.data.sort(profValLesser);return temp.data.front().second; }


IF you are goint to make a copy *anyway*, it is simpler to just pass by value and use the implicit copy:

// Oh, and we don't need 'typename' inside the template brackets here.friend const T pmin(Profile<T> temp) {  temp.data.sort(profValLesser);  return temp.data.front().second; }


BUT, we can in fact do much better, because there's no need to sort the whole list if we just need the smallest element:

friend const T pmin(const Profile<T>& profIn) {  return std::min_element(profIn.data.begin(), profIn.data.end())->second;}


And for that matter, why not just make it a member function? (With appropriate const correctness, of course.)

const T pmin() const {  return std::min_element(data.begin(), data.end())->second;}


As for mergeProfiles, I think we could do that at least as easily with a constructor:

// The first set doesn't have to "merge", because there are no elements in yet// for it to merge with. So we just copy them implicitly, via the initialization// list...Profile(const Profile<T>& a, const Profile<T>& b) : data(a.data) {  data.merge(b.data, profTimeLesser);}
Awesome. Worked great, with some minor modifications. I really appreciate the style advice. It's almost as valuable as the content itself because I'm an Aerospace Engineer learning C++ and my advisor doesn't catch style issues in my thesis code.

This topic is closed to new replies.

Advertisement