Nested templates and friends

Discussion in 'C++' started by Roger Leigh, Apr 15, 2004.

  1. Roger Leigh

    Roger Leigh Guest

    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>::eek:perator = (const numeric<Dpr>& rhs)
    { ... }

    template<unsigned short Dp>
    template<unsigned short Dpr>
    numeric<Dp>&
    numeric<Dp>::eek:perator += (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! =-----
    Roger Leigh, Apr 15, 2004
    #1
    1. Advertising

  2. Roger Leigh

    Roger Leigh Guest

    Roger Leigh <${roger}@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! =-----
    Roger Leigh, Apr 15, 2004
    #2
    1. Advertising

  3. Roger Leigh wrote in news: 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/
    Rob Williscroft, Apr 15, 2004
    #3
  4. 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
    Alberto Barbati, Apr 15, 2004
    #4
  5. Roger Leigh

    Roger Leigh Guest

    On 2004-04-15, Alberto Barbati <> 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! =-----
    Roger Leigh, Apr 21, 2004
    #5
  6. Roger Leigh

    Roger Leigh Guest

    On 2004-04-15, Rob Williscroft <> 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! =-----
    Roger Leigh, Apr 21, 2004
    #6
  7. Roger Leigh wrote in news:
    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/
    Rob Williscroft, Apr 21, 2004
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Buster Copley
    Replies:
    5
    Views:
    558
    Gianni Mariani
    Jul 7, 2003
  2. JKop
    Replies:
    3
    Views:
    468
  3. Replies:
    2
    Views:
    597
  4. recover
    Replies:
    2
    Views:
    799
    recover
    Jul 25, 2006
  5. Replies:
    0
    Views:
    656
Loading...

Share This Page