Template specialization | | |
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::ostream;
#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::ostream_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<in t>(cout));
cout<<'\n';
transform(myVec.begin(),myVec.end(),myVec.begin(), Add<int>(2));
copy(myVec.begin(),myVec.end(),ostream_iterator<in t >(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(),myMap.end(),ostream_iterator<pa ir<int,string>[color=blue]
>(cout));[/color]
transform(myMap.begin(),myMap.end(),myMap.begin(), Add<pair<int,string>[color=blue]
>("HaHaHa")); >>>>>>>>>>>>>Error here[/color]
copy(myMap.begin(),myMap.end(),ostream_iterator<pa ir<int,string>[color=blue]
>(cout));[/color]
while( !cin.get() );
return 0;
} | | | | re: Template specialization
On Thu, 22 Jul 2004 09:25:55 +0530, Senthilvel <Senthil@nospam.com> wrote:
There are quite a lot of reasons why your code should not compile,
including one that has no answer. See below
[color=blue]
>
> #pragma warning(disable: 4786)
> #include <iostream>
> using std::cout;
> using std::cin;
> using std::endl;
> using std::ostream;
> #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::ostream_iterator;[/color]
#include <functional>
using std::unary_function;
namespace std {
[color=blue]
> 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;
> }[/color]
}
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).
[color=blue]
> 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_;[/color]
U value_;
You cannot convert const U& to U&
[color=blue]
> 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<in t>(cout));
> cout<<'\n';
> transform(myVec.begin(),myVec.end(),myVec.begin(), Add<int>(2));
> copy(myVec.begin(),myVec.end(),ostream_iterator<in t >(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(),myMap.end(),ostream_iterator<pa ir<int,string>[color=green]
>> (cout));[/color]
> transform(myMap.begin(),myMap.end(),myMap.begin(), Add<pair<int,string>[color=green]
>> ("HaHaHa")); >>>>>>>>>>>>>Error here[/color][/color]
Transform uses assignment, but the value_type of a map is defined as
std::pair<const T, U>. Notice the const, this mean you cannot assign the
values in a map. So this is never going to work.
[color=blue]
> copy(myMap.begin(),myMap.end(),ostream_iterator<pa ir<int,string>[color=green]
>> (cout));[/color]
> while( !cin.get() );
> return 0;
> }
>[/color]
The other reason your code might not compile is if you are using VC++ 6
which doesn't support partial template speciialisation.
john | | | | re: Template specialization
"John Harrison" <john_andronicus@hotmail.com> wrote in message
news:opsbivnd0r212331@andronicus...[color=blue]
> On Thu, 22 Jul 2004 09:25:55 +0530, Senthilvel <Senthil@nospam.com> wrote:
>[/color]
[snip][color=blue]
> namespace std {
>[color=green]
> > 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;
> > }[/color]
>
> }
>
> 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).[/color]
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 | | | | re: Template specialization
On Thu, 22 Jul 2004 10:51:00 +0530, Sharad Kala
<no__spam.sharadk_ind@yahoo.com> wrote:
[color=blue]
>
> "John Harrison" <john_andronicus@hotmail.com> wrote in message
> news:opsbivnd0r212331@andronicus...[color=green]
>> On Thu, 22 Jul 2004 09:25:55 +0530, Senthilvel <Senthil@nospam.com>
>> wrote:
>>[/color]
> [snip][color=green]
>> namespace std {
>>[color=darkred]
>> > 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;
>> > }[/color]
>>
>> }
>>
>> 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).[/color]
>
> 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
>[/color]
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::ostream& operator<<(std::ostream& 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::ostream_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 | | | | re: Template specialization
"John Harrison" <john_andronicus@hotmail.com> wrote in message
news:opsbix3ek4212331@andronicus...[color=blue]
> On Thu, 22 Jul 2004 10:51:00 +0530, Sharad Kala
> <no__spam.sharadk_ind@yahoo.com> wrote:
>[color=green]
> >
> > "John Harrison" <john_andronicus@hotmail.com> wrote in message
> > news:opsbivnd0r212331@andronicus...[color=darkred]
> >> On Thu, 22 Jul 2004 09:25:55 +0530, Senthilvel <Senthil@nospam.com>
> >> wrote:
> >>[/color]
> > [snip][color=darkred]
> >> 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[/color][/color][/color]
my[color=blue][color=green][color=darkred]
> >> compiler).[/color]
> >
> > 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
> >[/color]
>
> 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::ostream& operator<<(std::ostream& 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::ostream_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.[/color]
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 | | | | re: Template specialization
> But you would agree that just because the code compiles on 3 top-notch[color=blue]
> compilers does not make it standard C++ compliant. Standard imposes no
> requirements on compiler vendors in case of UB.[/color]
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 |  | | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,471 network members.
|