Template specialization

S

Senthilvel

Hi ,
I am trying out a few templates and i got stuck in template specialization.
The normal template Add(just like a plus of the fubnctional) works fine.
But i wanted to specialize it for a map so that the value passed would be
added to the
mapped_value of each pair in the map.But the program fails to compile.

Can you kindly point out my error.
The source code is given below.

Thnaks and Best Regards,
Senthilvel.


#pragma warning(disable: 4786)

#include <iostream>
using std::cout;
using std::cin;
using std::endl;
using std::eek:stream;

#include <map>
using std::map;
using std::pair;

#include <vector>
using std::vector;

#include <algorithm>
using std::copy;
using std::transform;

#include <string>
using std::string;

#include <iterator>
using std::eek:stream_iterator;



template<class T,class U > ostream& operator << (ostream& os,const
pair<T,U>& val)
{
os<<"Key: " <<val.first<<endl;
os<<"Mapped Value: " << val.second<<endl;
return os;
}

template<class T,class U = T> struct Add:unary_function<T,U>
{
private:
T value_;
public:
Add(const T& val):value_(val){}
U operator()(const T& val)
{
return val + value_;
}
};


template<class T,class U> struct Add< pair<T,U> >:unary_function<
pair<T,U>,pair<T,U> >
{
private:
U& value_;
public:
Add(const U& val):value_(val){}
pair<T,U> operator()(const pair<T,U> & someVal)
{
U v = someVal.second + value_;
return make_pair(someVal.first,v);
}
};

int main()
{
/***********this block works fine ********************/
vector<int> myVec;
myVec.push_back(100);
myVec.push_back(100);
myVec.push_back(100);
myVec.push_back(100);
myVec.push_back(100);

copy(myVec.begin(),myVec.end(),ostream_iterator<int>(cout));
cout<<'\n';
transform(myVec.begin(),myVec.end(),myVec.begin(),Add<int>(2));
copy(myVec.begin(),myVec.end(),ostream_iterator<int >(cout));
cout<<'\n';
/************************************************/
map<int,string> myMap;
myMap[0] = "Senthil";
myMap[1] = "Sreeni";
myMap[2] = "Chandy";
myMap[3] = "Satish";
myMap[4] = "Taruna";

copy(myMap.begin() said:
transform(myMap.begin() said:
("HaHaHa")); >>>>>>>>>>>>>Error here
copy(myMap.begin() said:


while( !cin.get() );
return 0;
}
 
J

John Harrison

There are quite a lot of reasons why your code should not compile,
including one that has no answer. See below
#pragma warning(disable: 4786)
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
using std::eek:stream;
#include <map>
using std::map;
using std::pair;
#include <vector>
using std::vector;
#include <algorithm>
using std::copy;
using std::transform;
#include <string>
using std::string;
#include <iterator>
using std::eek:stream_iterator;

#include <functional>
using std::unary_function;

namespace std {
template<class T,class U > ostream& operator << (ostream& os,const
pair<T,U>& val)
{
os<<"Key: " <<val.first<<endl;
os<<"Mapped Value: " << val.second<<endl;
return os;
}

}

The operator<< for pairs should be defined in the std namespace (at least
I think so, I certainly had to do this to get your code to compile on my
compiler).
template<class T,class U = T> struct Add:unary_function<T,U>
{
private:
T value_;
public:
Add(const T& val):value_(val){}
U operator()(const T& val)
{
return val + value_;
}
};
template<class T,class U> struct Add< pair<T,U> >:unary_function<
pair<T,U>,pair<T,U> >
{
private:
U& value_;

U value_;

You cannot convert const U& to U&
public:
Add(const U& val):value_(val){}
pair<T,U> operator()(const pair<T,U> & someVal)
{
U v = someVal.second + value_;
return make_pair(someVal.first,v);
}
};
int main()
{
/***********this block works fine ********************/
vector<int> myVec;
myVec.push_back(100);
myVec.push_back(100);
myVec.push_back(100);
myVec.push_back(100);
myVec.push_back(100);
copy(myVec.begin(),myVec.end(),ostream_iterator<int>(cout));
cout<<'\n';
transform(myVec.begin(),myVec.end(),myVec.begin(),Add<int>(2));
copy(myVec.begin(),myVec.end(),ostream_iterator<int >(cout));
cout<<'\n';
/************************************************/
map<int,string> myMap;
myMap[0] = "Senthil";
myMap[1] = "Sreeni";
myMap[2] = "Chandy";
myMap[3] = "Satish";
myMap[4] = "Taruna";
copy(myMap.begin() said:
transform(myMap.begin() said:
("HaHaHa")); >>>>>>>>>>>>>Error here

Transform uses assignment, but the value_type of a map is defined as
while( !cin.get() );
return 0;
}

The other reason your code might not compile is if you are using VC++ 6
which doesn't support partial template speciialisation.

john
 
S

Sharad Kala

John Harrison said:
[snip]
namespace std {
template<class T,class U > ostream& operator << (ostream& os,const
pair<T,U>& val)
{
os<<"Key: " <<val.first<<endl;
os<<"Mapped Value: " << val.second<<endl;
return os;
}

}

The operator<< for pairs should be defined in the std namespace (at least
I think so, I certainly had to do this to get your code to compile on my
compiler).

Hey John,

This is a quote from Section 17.4.3.1/1
"It is undefined for a C++ program to add declarations or definitions to
namespace std or namespaces within namespace std unless otherwise specified.
A program may add template specializations for any standard library template
to namespace std. Such a specialization (complete or partial) of a standard
library template results in undefined behavior unless the declaration
depends on a user-defined name of external linkage and unless the
specialization meets the standard library requirements for the original
template"

Is it kosher to add this in std namespace in light of this quote? Of course
I could be wrong in interpreting the standard or what you meant.

Regards,
Sharad
 
J

John Harrison

John Harrison said:
[snip]
namespace std {
template<class T,class U > ostream& operator << (ostream& os,const
pair<T,U>& val)
{
os<<"Key: " <<val.first<<endl;
os<<"Mapped Value: " << val.second<<endl;
return os;
}

}

The operator<< for pairs should be defined in the std namespace (at
least
I think so, I certainly had to do this to get your code to compile on my
compiler).

Hey John,

This is a quote from Section 17.4.3.1/1
"It is undefined for a C++ program to add declarations or definitions to
namespace std or namespaces within namespace std unless otherwise
specified.
A program may add template specializations for any standard library
template
to namespace std. Such a specialization (complete or partial) of a
standard
library template results in undefined behavior unless the declaration
depends on a user-defined name of external linkage and unless the
specialization meets the standard library requirements for the original
template"

Is it kosher to add this in std namespace in light of this quote? Of
course
I could be wrong in interpreting the standard or what you meant.

Regards,
Sharad

Here's a simpler version of the same code

#include <iostream>
#include <utility>
#include <map>
#include <algorithm>
#include <iterator>

namespace std
{
template <class T, class U>
std::eek:stream& operator<<(std::eek:stream& out, std::pair<T, U> const& p)
{
return out << p.first << ' ' << p.second;
}
}

int main()
{
std::map<int, int> m;
std::copy(m.begin(), m.end(),
std::eek:stream_iterator<std::map<int, int>::value_type>(std::cout));
}

This compiles on VC++ 7.1, gcc 3.3.1 and Comeau C++, if I declare
operator<< in the global namespace instead then it fails to compile on any
of these.

But the quote you made seems to rule this out, since what I've added to
the std namespace is not a template specialisation but an overloaded
function. So I don't know what to think.

john
 
S

Sharad Kala

John Harrison said:
John Harrison said:
[snip]
namespace std {

template<class T,class U > ostream& operator << (ostream& os,const
pair<T,U>& val)
{
os<<"Key: " <<val.first<<endl;
os<<"Mapped Value: " << val.second<<endl;
return os;
}

}

The operator<< for pairs should be defined in the std namespace (at
least
I think so, I certainly had to do this to get your code to compile on my
compiler).

Hey John,

This is a quote from Section 17.4.3.1/1
"It is undefined for a C++ program to add declarations or definitions to
namespace std or namespaces within namespace std unless otherwise
specified.
A program may add template specializations for any standard library
template
to namespace std. Such a specialization (complete or partial) of a
standard
library template results in undefined behavior unless the declaration
depends on a user-defined name of external linkage and unless the
specialization meets the standard library requirements for the original
template"

Is it kosher to add this in std namespace in light of this quote? Of
course
I could be wrong in interpreting the standard or what you meant.

Regards,
Sharad

Here's a simpler version of the same code

#include <iostream>
#include <utility>
#include <map>
#include <algorithm>
#include <iterator>

namespace std
{
template <class T, class U>
std::eek:stream& operator<<(std::eek:stream& out, std::pair<T, U> const& p)
{
return out << p.first << ' ' << p.second;
}
}

int main()
{
std::map<int, int> m;
std::copy(m.begin(), m.end(),
std::eek:stream_iterator<std::map<int, int>::value_type>(std::cout));
}

This compiles on VC++ 7.1, gcc 3.3.1 and Comeau C++, if I declare
operator<< in the global namespace instead then it fails to compile on any
of these.

But the quote you made seems to rule this out, since what I've added to
the std namespace is not a template specialisation but an overloaded
function. So I don't know what to think.

But you would agree that just because the code compiles on 3 top-notch
compilers does not make it standard C++ compliant. Standard imposes no
requirements on compiler vendors in case of UB.
I modified your code to print some values to see it's run time behavior and
it actually worked fine on VC 7 and g++ 3.3.1 ;-)
I quickly skimmed the defect report too but could not find anything to the
extent to claim the above code legal.

-Sharad
 
J

John Harrison

But you would agree that just because the code compiles on 3 top-notch
compilers does not make it standard C++ compliant. Standard imposes no
requirements on compiler vendors in case of UB.

Of course, perhaps this would make a good question for a new thread, see
what the gurus make of it.

And the other side of the coin is why those compiler are right (if they are
right) to reject the code when operator<< is defined in the global
namespace.

If they are right to reject that, and if it is wrong to define operator<<
for std::pair in the std namespace then there would seem to be no way to
define operator<< for any class in the std namespace.

john
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top