469,138 Members | 1,343 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,138 developers. It's quick & easy.

Nested templates and friends

I've written a fixed-precision class, "numeric". This stores the
number of decimal places as a template parameter. I've overloaded all
of the normal numerical operators (an example):

[Dp is the number of decimal places in the left-hand operand, and Dpr
the number in the right-hand operand.]

template<unsigned short Dp>
class numeric {
public:
// Round mode and precision are not assigned.
template<unsigned short Dpr>
numeric& operator = (const numeric<Dpr>& rhs);

template<unsigned short Dpr>
numeric& operator += (const numeric<Dpr>& rhs);

template<unsigned short Dpr>
friend numeric operator + <>(const numeric& lhs,
const numeric<Dpr>& rhs);
};

The implementation is like this:

template<unsigned short Dp>
template<unsigned short Dpr>
numeric<Dp>&
numeric<Dp>::operator = (const numeric<Dpr>& rhs)
{ ... }

template<unsigned short Dp>
template<unsigned short Dpr>
numeric<Dp>&
numeric<Dp>::operator += (const numeric<Dpr>& rhs)
{ ... }

template<unsigned short Dp>
template<unsigned short Dpr>
numeric<Dp> operator + (const numeric<Dp>& lhs,
const numeric<Dpr>& rhs)
{ ... }
While the unary operators are fine, I can't get the binary operator, a
friend, to work. I'm sure this is an issue with the template syntax,
but I can't work out what's wrong. I can't add the first template
list to the declaration, since it's within the class declaration, and
removing the <> makes no difference.
Thanks,
Roger

--
Roger Leigh

Printing on GNU/Linux? http://gimp-print.sourceforge.net/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----
Jul 22 '05 #1
6 1313
Roger Leigh <${******@invalid.whinlatter.uklinux.net.invalid > writes:

Changing this
template<unsigned short Dpr>
friend numeric operator + <>(const numeric& lhs,
const numeric<Dpr>& rhs);
};
to this

template<unsigned short Dpr>
friend numeric operator + (const numeric& lhs,
const numeric<Dpr>& rhs);

and this
template<unsigned short Dp>
template<unsigned short Dpr>
numeric<Dp> operator + (const numeric<Dp>& lhs,
const numeric<Dpr>& rhs)
{ ... }


to this

template<unsigned short Dp, unsigned short Dpr>
numeric<Dp> operator + (const numeric<Dp>& lhs,
const numeric<Dpr>& rhs)
{ ... }

has solved this problem, though I'm not clear *why* this is the case.
My (hopefully last) remaining problem is a templated copy constructor
and assignment operator:

template<unsigned short Dp>
class numeric {
public:
template<unsigned short Dpr>
numeric (const numeric<Dpr>& rhs);
};

template<unsigned short Dp>
template<unsigned short Dpr>
EPIC::numeric<Dp>::numeric(const EPIC::numeric<Dpr>& rhs):
{ ... }

If I use "template<unsigned short Dp, unsigned short Dpr>" it's still
unhappy:

.../util/numeric.tcc:70: error: prototype for `numeric<Dp>::numeric(const
numeric<Dp>&)' does not match any in class `numeric<Dp>'

How should I declare/define this?
Thanks,
Roger

--
Roger Leigh

Printing on GNU/Linux? http://gimp-print.sourceforge.net/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----
Jul 22 '05 #2
Roger Leigh wrote in news:87************@wrynose.whinlatter.uklinux.net in
comp.lang.c++:
template<unsigned short Dp>
template<unsigned short Dpr>
numeric<Dp> operator + (const numeric<Dp>& lhs,
const numeric<Dpr>& rhs)
{ ... }
to this

template<unsigned short Dp, unsigned short Dpr>
numeric<Dp> operator + (const numeric<Dp>& lhs,
const numeric<Dpr>& rhs)
{ ... }

has solved this problem, though I'm not clear *why* this is the case.


template <...> template <...> is for member templates of template
classes, your operator + is a non-member function.
My (hopefully last) remaining problem is a templated copy constructor
and assignment operator:

template<unsigned short Dp>
class numeric {
public:
template<unsigned short Dpr>
numeric (const numeric<Dpr>& rhs);
};

template<unsigned short Dp>
template<unsigned short Dpr>
EPIC::numeric<Dp>::numeric(const EPIC::numeric<Dpr>& rhs):
{ ... }

Can you compile this:

#include <iostream>
#include <ostream>

template < unsigned D >
struct num
{
template < unsigned Dr > num( num< Dr > const &rhs );
num() {};
};

template < unsigned D >
template < unsigned Dr >
num< D >::num( num< Dr > const & )
{
std::cout << "template ctor" << std::endl;
}
int main()
{
num< 10 > n10;
num< 12 > n12( n10 );
}
If I use "template<unsigned short Dp, unsigned short Dpr>" it's still
unhappy:
As it should be.

../util/numeric.tcc:70: error: prototype for `numeric<Dp>::numeric>
(const numeric<Dp>&)' does not match any in class `numeric<Dp>'

It maybe a bug in your compiler but surely it should be:
(const numeric< Dpr >&) in the above error message.
How should I declare/define this?


namespace EPIC /* 'EPIC' BTW looks like a macro */
{
template<unsigned short Dp>
template<unsigned short Dpr>
numeric<Dp>::numeric(const numeric<Dpr>& rhs):
{
// ...
}
} /* EPIC:: */

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #3
Roger Leigh wrote:

template<unsigned short Dp, unsigned short Dpr>
numeric<Dp> operator + (const numeric<Dp>& lhs,
const numeric<Dpr>& rhs)
{ ... }

Do you realize that your operator+ is not commutative? Expressions like
(a + b) and (b + a) could have a different types and therefore
different values, so this design looks quite error-prone to me.

It would be better to return a numeric<Dpm> where Dpm is the max between
Dp and Dpr. It's a bit tricky as a few compilers (as VC7.1, for example)
chokes about the ?: operator used in a template argument. You may try this:

template <unsigned short N, unsigned short M>
struct static_max
{
static const unsigned short value = (N > M ? N : M);
};

template <unsigned short Dp, unsigned short Dpr>
numeric< static_max<Dp, Dpr>::value >
operator+(const numeric<Dp>& lhs, const numeric<Dpr> rhs)
{...}

../util/numeric.tcc:70: error: prototype for `numeric<Dp>::numeric(const
numeric<Dp>&)' does not match any in class `numeric<Dp>'


This error message is suspicious because it should have mentioned
numeric<Dp>::numeric(const numeric<Dpr>&) instead. Did you declare a
copy constructor? Unless you are happy with the implictly generated one,
you should declare it, as a template constructor is never used as a copy
constructor.

Alberto
Jul 22 '05 #4
On 2004-04-15, Alberto Barbati <Al************@libero.it> wrote:
Roger Leigh wrote:

template<unsigned short Dp, unsigned short Dpr>
numeric<Dp> operator + (const numeric<Dp>& lhs,
const numeric<Dpr>& rhs)
{ ... }

Do you realize that your operator+ is not commutative? Expressions like
(a + b) and (b + a) could have a different types and therefore
different values, so this design looks quite error-prone to me.


You're right. After thinking about this, I decided on the following
design:

class numeric_base
{
protected:
numeric_base(unsigned short dp): m_dp(dp) {}
private:
unsigned short m_dp;
}

template<unsigned short Dp>
class numeric
{
public:
numeric(): numeric_base(Dp) {}
}

This has the nice property of only needing to define all the operators
in the numeric_base class, which the template then uses. The template
does nothing but give a default m_dp value.
It would be better to return a numeric<Dpm> where Dpm is the max between
Dp and Dpr. It's a bit tricky as a few compilers (as VC7.1, for example)
chokes about the ?: operator used in a template argument. You may try this:

template <unsigned short N, unsigned short M>
struct static_max
{
static const unsigned short value = (N > M ? N : M);
};

template <unsigned short Dp, unsigned short Dpr>
numeric< static_max<Dp, Dpr>::value >
operator+(const numeric<Dp>& lhs, const numeric<Dpr> rhs)
{...}


That looks quite clever, but I like to keep template magic to the
minimum, so that both I and those I work with can understand it!
../util/numeric.tcc:70: error: prototype for `numeric<Dp>::numeric(const
numeric<Dp>&)' does not match any in class `numeric<Dp>'


This error message is suspicious because it should have mentioned
numeric<Dp>::numeric(const numeric<Dpr>&) instead. Did you declare a
copy constructor? Unless you are happy with the implictly generated one,
you should declare it, as a template constructor is never used as a copy
constructor.


Ah, I didn't realise that. So I need both a template constructor and a
copy constructor.
Thanks,
Roger

--
Roger Leigh

Printing on GNU/Linux? http://gimp-print.sourceforge.net/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----
Jul 22 '05 #5
On 2004-04-15, Rob Williscroft <rt*@freenet.co.uk> wrote:
My (hopefully last) remaining problem is a templated copy constructor
and assignment operator:

template<unsigned short Dp>
class numeric {
public:
template<unsigned short Dpr>
numeric (const numeric<Dpr>& rhs);
};

template<unsigned short Dp>
template<unsigned short Dpr>
EPIC::numeric<Dp>::numeric(const EPIC::numeric<Dpr>& rhs):
{ ... }


Can you compile this:

#include <iostream>
#include <ostream>

template < unsigned D >
struct num
{
template < unsigned Dr > num( num< Dr > const &rhs );
num() {};
};

template < unsigned D >
template < unsigned Dr >
num< D >::num( num< Dr > const & )
{
std::cout << "template ctor" << std::endl;
}


This works just fine (with GCC 3.3.3). However, I've changed the design
to remove the need for the template complexity.

Could anyone recommend any book or online documentation about the rules
for template syntax? I find it quite confusing. The books I have only
go into the basic usage of existing templates, and leave all this stuff
untouched.
One last template question:

If a library defines a templated function:

template<typename T>
do_foo(const T& object)
{ }

and the user is required to specalise it for their type:

class mytype;

template<>
do_foo(const mytype& object)
{ }

how should one specialise for a templated type?

template<typename T>
class mytype;

template<????>
do_foo(const mytype<??>& object)
{ }

I've tried quite a few things, like
template<> template<typename T>
but the compiler wasn't happy with any of them. Is this possible to do,
or does it require specialisation for every mytype<T> I use?
Thanks,
Roger

--
Roger Leigh

Printing on GNU/Linux? http://gimp-print.sourceforge.net/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----
Jul 22 '05 #6
Roger Leigh wrote in news:tn************@system10.lan.epictechnology.co .uk
in comp.lang.c++:

If a library defines a templated function:

template<typename T>
do_foo(const T& object)
{ }
No return type.

and the user is required to specalise it for their type:

class mytype;

template<>
do_foo(const mytype& object)
{ }

how should one specialise for a templated type?

template<typename T>
class mytype;

template<????>
do_foo(const mytype<??>& object)
{ }

I've tried quite a few things, like
template<> template<typename T>
but the compiler wasn't happy with any of them. Is this possible to do,
or does it require specialisation for every mytype<T> I use?


#include <iostream>
#include <ostream>

template<typename T>
void do_foo( T const & )
{
std::cout << "do_foo< T >( T const & )" << std::endl;
}
class mytype
{
};

template<>
void do_foo( mytype const & )
{
std::cout << "do_foo< mytype >( mytype const & )" << std::endl;
}

template < typename T >
class myclass_template
{
};

template < typename T >
void do_foo( myclass_template< T > const & )
{
std::cout << "do_foo< T >( myclass_template< T > const & )" << std::endl;
}

/* The above is an *overload* of do_foo< T >( T const & ), it differs
only in argument type. The previous function do_foo< mytype > is a
specialization.
*/
int main()
{
do_foo( 0 );

mytype a;
do_foo( a );

myclass_template< int > b;
do_foo( b );
}
Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

1 post views Thread by Alexander Stippler | last post: by
1 post views Thread by Gianni Mariani | last post: by
6 posts views Thread by oooooo0000000 | last post: by
3 posts views Thread by Andriy Shnyr | last post: by
8 posts views Thread by Robert W. | last post: by
25 posts views Thread by Ted | last post: by
3 posts views Thread by CrazyAtlantaGuy | last post: by
4 posts views Thread by aaragon | last post: by
reply views Thread by zhoujie | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.