Limiting classes that a template parameter can be interpreted as



 DEVELOP > c-Plus-Plus > Limiting classes that a template parameter can be interpreted as

LINK TO THIS PAGE  


rating :  0   |  0


  Page 1 of 1

1

 
Topic: DEVELOP > c-Plus-Plus
User: "Chris Swiedler"
Date: 03 Feb 2008 03:05:09 PM
Object: Limiting classes that a template parameter can be interpreted as
How do I limit a template parameter to a specific set of classes? If I
write code like
class MyStream1
{
public:
void Write(...) {}
};
class MyStream2
{
public:
void Write(...) {}
};
template <class S> S & operator<<(S &lhs, int rhs) { lhs.Write(rhs);
return lhs; }
MyStream1 ms1;
MyStream2 ms2;
ms1 << 5;
ms2 << 5;
std::cout << 5;
.... then the compiler complains that ostream doesn't have a Write
method, i.e. it's using my overloaded free operator<< to stream into
an ostream, which is obviously bad. I then tried:
class MyStream1
{
public:
typedef MyStream1 StreamType;
void Write(...) {}
};
class MyStream2
{
public:
typedef MyStream2 StreamType;
void Write(...) {}
};
template <class S> class S::StreamType & operator<< (class
S::StreamType &lhs, int rhs) { lhs.Write(rhs); return lhs;}
MyStream1 ms1;
MyStream2 ms2;
ms1 << 5;
ms2 << 5;
std::cout << 5;
When I do this, it no longer tries to use my overload for the ostream,
but instead complains that there is no valid overloaded operator<< for
MyStream1 or MyStream2. Is this nested typedef a valid way to limit my
overload to my own classes? Is there another way to do this?
I've actually switched away from this technique to using a base class
which implements Write(), and having the operator<< take the base
class as its first parameter. Still, I'm curious how I might
accomplish this.
chris
.

User: "Alf P. Steinbach"

Title: Re: Limiting classes that a template parameter can be interpretedas 03 Feb 2008 03:18:41 PM
* Chris Swiedler:

How do I limit a template parameter to a specific set of classes? If I
write code like

class MyStream1
{
public:
void Write(...) {}
};

class MyStream2
{
public:
void Write(...) {}
};

template <class S> S & operator<<(S &lhs, int rhs) { lhs.Write(rhs);
return lhs; }

MyStream1 ms1;
MyStream2 ms2;
ms1 << 5;
ms2 << 5;
std::cout << 5;

... then the compiler complains that ostream doesn't have a Write
method, i.e. it's using my overloaded free operator<< to stream into
an ostream, which is obviously bad. I then tried:

class MyStream1
{
public:
typedef MyStream1 StreamType;

void Write(...) {}
};

class MyStream2
{
public:
typedef MyStream2 StreamType;

void Write(...) {}
};

template <class S> class S::StreamType & operator<< (class
S::StreamType &lhs, int rhs) { lhs.Write(rhs); return lhs;}

That would need to be
template< class S >
typename S::StreamType& operator<<(
typename S::StreamType& lhs, int rhs
);

MyStream1 ms1;
MyStream2 ms2;
ms1 << 5;
ms2 << 5;
std::cout << 5;

When I do this, it no longer tries to use my overload for the ostream,
but instead complains that there is no valid overloaded operator<< for
MyStream1 or MyStream2. Is this nested typedef a valid way to limit my
overload to my own classes?

No, not even if you defined operator<< in a technically correct way as
shown above.
Template parameter deduction fails.

Is there another way to do this?

I've actually switched away from this technique to using a base class
which implements Write(), and having the operator<< take the base
class as its first parameter. Still, I'm curious how I might
accomplish this.

You don't need to use boost::enable_if.
Just add a namespace:
#include <iostream>
namespace my
{
class Stream1
{
public:
void Write(...) {}
};
class Stream2
{
public:
void Write(...) {}
};
template< class S >
S& operator<<( S& lhs, int rhs )
{
lhs.Write( rhs ); return lhs;
}
}
int main()
{
my::Stream1 ms1;
my::Stream2 ms2;
ms1 << 5;
ms2 << 5;
std::cout << 5;
}
The prefix "My" you had indicates a namespace anyway...
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
.
User: "Chris Swiedler"

Title: Re: Limiting classes that a template parameter can be interpreted as 03 Feb 2008 10:56:35 PM

template <class S> class S::StreamType & operator<< (class
S::StreamType &lhs, int rhs) { lhs.Write(rhs); return lhs;}


That would need to be

template< class S >
typename S::StreamType& operator<<(
typename S::StreamType& lhs, int rhs
);

Yes, that's what I meant, thanks.

You don't need to use boost::enable_if.

Just add a namespace:

#include <iostream>

namespace my
{
class Stream1
{
public:
void Write(...) {}
};

class Stream2
{
public:
void Write(...) {}
};

template< class S >
S& operator<<( S& lhs, int rhs )
{
lhs.Write( rhs ); return lhs;
}
}

I'm confused as to why this helps. How do namespaces affect template
parameter resolution and function overload choice? Are template
parameters in free functions which are defined in a namespace only
allowed to resolve to types in that namespace? Are free function
overloads of operator<< only used if they're in the same namespace as
the code which invokes them?
thanks,
chris
.
User: "Alf P. Steinbach"

Title: Re: Limiting classes that a template parameter can be interpretedas 04 Feb 2008 05:35:44 AM
* Chris Swiedler:

template <class S> class S::StreamType & operator<< (class
S::StreamType &lhs, int rhs) { lhs.Write(rhs); return lhs;}

That would need to be

template< class S >
typename S::StreamType& operator<<(
typename S::StreamType& lhs, int rhs
);


Yes, that's what I meant, thanks.

You don't need to use boost::enable_if.

Just add a namespace:

#include <iostream>

namespace my
{
class Stream1
{
public:
void Write(...) {}
};

class Stream2
{
public:
void Write(...) {}
};

template< class S >
S& operator<<( S& lhs, int rhs )
{
lhs.Write( rhs ); return lhs;
}
}


I'm confused as to why this helps. How do namespaces affect template
parameter resolution and function overload choice? Are template
parameters in free functions which are defined in a namespace only
allowed to resolve to types in that namespace? Are free function
overloads of operator<< only used if they're in the same namespace as
the code which invokes them?

With the whole thing in a namespace, and no "using...", the above
operator<< is only found via argument-dependent lookup (ADL). And ADL
doesn't find it for use of operator<< with the standard iostreams.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
.
User: "Chris Swiedler"

Title: Re: Limiting classes that a template parameter can be interpreted as 04 Feb 2008 11:35:17 AM

With the whole thing in a namespace, and no "using...", the above
operator<< is only found via argument-dependent lookup (ADL). And ADL
doesn't find it for use of operator<< with the standard iostreams.

If I understand correctly, in the case of templated parameters, the
actual type of the parameter passed in is used to find the correct
free function? Which is why I get the following:
class A { };
namespace NS
{
class B { };
template <typename T> void f( T t ) {}
void works()
{
::A a;
NS::B b;
f(a);
f(b);
}
};
void doesnt_work()
{
::A a;
NS::B b;
f(a); // error, can't find f() which takes an ::A
f(b);
}
Therefore, if I define my free operator<< function in a namespace,
code outside the namespace will not find it, but anything inside the
namespace will. That explains my actual problem, which was with some
code which streamed into a stringstream, located inside the same
namespace as the operator<<.
thanks,
chris
.
User: "Alf P. Steinbach"

Title: Re: Limiting classes that a template parameter can be interpretedas 04 Feb 2008 11:42:39 AM
* Chris Swiedler:

With the whole thing in a namespace, and no "using...", the above
operator<< is only found via argument-dependent lookup (ADL). And ADL
doesn't find it for use of operator<< with the standard iostreams.


If I understand correctly, in the case of templated parameters,

Well, ADL is not restricted to templates.
It's the same for ordinary functions.

the
actual type of the parameter passed in is used to find the correct
free function?

Yes.
Cheers,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
.





User: "Juha Nieminen"

Title: Re: Limiting classes that a template parameter can be interpretedas 04 Feb 2008 08:01:33 AM
Chris Swiedler wrote:

How do I limit a template parameter to a specific set of classes?

If I'm not completely mistaken, the upcoming C++ standard will define
new syntax for this exact purpose. (Its main goal is to make it easier
for compilers to generate legible error messages when something which
requires iterators is given the wrong type of iterator (or something
which is not an iterator at all).)
.


  Page 1 of 1

1

 


Related Articles
A Template that rejects classes.
Wii
Declaring Template Classes that take Multiple Nested Templates as Parameters
Specialisation of a template that results to another template
Template virtual member method is not allowed. How to bypass that?
template function that accepts const and non-const
xlc - A template dependent name that is a type must be qualified with "typename"
Class template parameter that is a function
c++
Template that can take variable number of arguments
It's strange that the address of array elements are not acceptable template-arguments!!
how to do that, one problem in Template. help!!!
specialize a template function that contains a template parameter
Canceling file or directory deletion in .NET. That's Right Tony. How Dare You Ask a Question About .NET in This Dictatorship?
How to write C++ code that compiles in Windows/Linux
 

NEWER

pg.1232     pg.940     pg.716     pg.544     pg.412     pg.311     pg.234     pg.175     pg.130     pg.96     pg.70     pg.50     pg.35     pg.24     pg.16     pg.10     pg.6     pg.3     pg.1

OLDER