Topic: template member function syntax


Author: Alex Vinokur <alexander.vinokur@telrad.co.il>
Date: 1999/02/08
Raw View
In article <79dfr4$jna$1@engnews2.Eng.Sun.COM>,
  clamage@Eng.Sun.COM (Steve Clamage) wrote:

[snip]
>
> I got this one wrong. The "template" keyword is only needed in a
> template definition when you have something depending on a template
> parameter. The situation is the same as needing "typename" to
> specify whether a dependant name is a type. Example:
>
> template< class T > void f( T t )
> {
>     t.g<int>();          // error
>     t.template g<int>(); // OK
> }
>
> In the first case, it can't be known whether g is a template name,
> so it can't be known whether the < is a template bracket or a
> less-than. Without the "template" keyword, the rule is that
> g is not a template name, and the expression is ill-formed.
>
>
[snip]

Hi,

There is a difference between
        1) syntax of template (usual) function with arguments
        2) syntax of template (usual) function without arguments
        3) syntax of template member function with arguments
        4) syntax of template member function without arguments

This difference is demonstrated in the following example.

        Alex

###################################################
############# 1. MyClass.h ########################
###################################################

#include <string>

//############################################
// template (usual) function with arguments
template <typename T1, typename T2>
void foo1(T1 &a, T2 &b)
{
        cout << __PRETTY_FUNCTION__ << " : a = " << a << endl;
           // __PRETTY_FUNCTION__ is  predefined string variable in gcc/g++
        cout << __PRETTY_FUNCTION__ << " : b = " << b << endl;
        cout << endl;
}

//############################################
// template (usual) function without arguments
template <typename T1, typename T2>
void foo2()
{
        cout << __PRETTY_FUNCTION__ << " : No input parameters" << endl;

        cout << endl;
}

//############################################
class MyClass
{
public:
        MyClass () {}
        ~MyClass () {}

        template <typename T1, typename T2>
        void Foo1(T1 &a, T2 &b);

        template <typename T1, typename T2>
        void Foo2();

private:
};

//-------------------------
// template member function with arguments
template <typename T1, typename T2>
void MyClass::Foo1(T1 &a, T2 &b)
{
        cout << __PRETTY_FUNCTION__ << " : a = " << a << endl;
        cout << __PRETTY_FUNCTION__ << " : b = " << b << endl;
        cout << endl;
}

//-------------------------
// template member function without arguments
template <typename T1, typename T2>
void MyClass::Foo2()
{
        cout << __PRETTY_FUNCTION__ << " : No input parameters" << endl;

        cout << endl;
}

###################################################
############# 2. MyClass.cpp ######################
###################################################

#include "MyClass.h"

###################################################
############# 3. main.cpp ######################
###################################################

#include "MyClass.h"
int main ()
{
MyClass my;
int     i1 = 123;
int     i2 = 79;
char*   c1 = "abcd";
char*   c2 = "xyz";

        // template (usual) function with arguments
        cout << "###### foo1 ######" << endl;
        foo1 (i1, i2);
        foo1 (i1, c2);
        foo1 (c1, c2);
        foo1 (c1, i2);

        // template (usual) function without arguments
        cout << "###### foo2 ######" << endl;
        foo2<int, int> ();
        foo2<int, char*> ();
        foo2<char*, int> ();
        foo2<char*, char*> ();

        // template member function with arguments
        cout << "###### MyClass::Foo1 ######" << endl;
        my.Foo1 (i1, i2);
        my.Foo1 (i1, c2);
        my.Foo1 (c1, c2);
        my.Foo1 (c1, i2);

        // template member function without arguments
        cout << "###### MyClass::Foo2 ######" << endl;
        my.template Foo2<int, int> ();
        my.template Foo2<int, char*> ();
        my.template Foo2<char*, int> ();
        my.template Foo2<char*, char*> ();

        return 0;
}

###################################################
############# 4. Compiler #########################
###################################################

g++ -v : gcc version egcs-2.91.57 19980901 (egcs-1.1 release)

###################################################
############# 5. Hardware #########################
###################################################

uname -a : SunOS tibamsun8 5.6 Generic_105181-09 sun4m sparc
SUNW,SPARCstation-5

###################################################
############# 6. Results of the running  ##########
###################################################


###### foo1 ######
void foo1<int, int>(int &, int &) : a = 123
void foo1<int, int>(int &, int &) : b = 79

void foo1<int, char *>(int &, char *&) : a = 123
void foo1<int, char *>(int &, char *&) : b = xyz

void foo1<char *, char *>(char *&, char *&) : a = abcd
void foo1<char *, char *>(char *&, char *&) : b = xyz

void foo1<char *, int>(char *&, int &) : a = abcd
void foo1<char *, int>(char *&, int &) : b = 79

###### foo2 ######
void foo2<int, int>() : No input parameters

void foo2<int, char *>() : No input parameters

void foo2<char *, int>() : No input parameters

void foo2<char *, char *>() : No input parameters

###### MyClass::Foo1 ######
void MyClass::Foo1<int, int>(int &, int &) : a = 123
void MyClass::Foo1<int, int>(int &, int &) : b = 79

void MyClass::Foo1<int, char *>(int &, char *&) : a = 123
void MyClass::Foo1<int, char *>(int &, char *&) : b = xyz

void MyClass::Foo1<char *, char *>(char *&, char *&) : a = abcd
void MyClass::Foo1<char *, char *>(char *&, char *&) : b = xyz

void MyClass::Foo1<char *, int>(char *&, int &) : a = abcd
void MyClass::Foo1<char *, int>(char *&, int &) : b = 79

###### MyClass::Foo2 ######
void MyClass::Foo2<int, int>() : No input parameters

void MyClass::Foo2<int, char *>() : No input parameters

void MyClass::Foo2<char *, int>() : No input parameters

void MyClass::Foo2<char *, char *>() : No input parameters

###################################################
############# END of INFORMATION  #################
###################################################



-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Biju Thomas <bijuthom@ibm.net>
Date: 1999/02/04
Raw View
Steve Clamage wrote:
>
> >>     myType mytmp = MyObj.template myFunc<myType>();
> >>                          ^^^^^^^^?
> No, it is required to allow parsing of general expressions like
>         A . B < C > ( D )
>
> If A has a static member B, A.B is its address. The address
> could be compared with C, and the result compared with D
> (the parens are redundant).
>
> But if B is a template function member of A, we have a
> function call as in the original code.
>
> You can't tell in general whether the '<' is a template
> bracket or a less-than. To make the determination, you need
> to know whether myFunc is the name of a template. To know
> that you need to know what scopes to look in.  To know that,
> you need to know whether the < is a template bracket.

Is it that difficult?

To determine whether B is a template, the compiler has to lookup in the
scope of the class of the A object.

Why does the compiler need to know whether B is a template member to
find out the scope for name lookup?

Regards,
Biju Thomas
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Biju Thomas <bijuthom@ibm.net>
Date: 1999/02/04
Raw View
hursh wrote:
>
>     I recently spent a few hours trying to find the syntax for what I
> had expected to be:
>
>      myType mytmp = MyObj.myFunc<myType>();
>
> The `proper' syntax seems to be:
>
>      myType mytmp = MyObj.template myFunc<myType>();
>                           ^^^^^^^^?
>   I understand the the syntax error of myType being after the
> less-than operator, but putting the template keyword in the invocation
> just seems plain ugly.  Is there a more convenient way of doing this
> that I missed?

No.

However, it will be better if C++ removed this help-the-compiler-writer
feature. C++ compilers already handle enough context-sensitivity in the
parsing phase. It won't be difficult to add a little more
context-sensivity into the compiler.

> If not, was it because this type of
> declaration/invoation is considered *bad*, and hence should be made to
> look bad?  (Kinda like the newer casts.)

I don't think so. There is nothing bad about member templates.

Was the new cast styles designed to look bad? I thought they were
designed so that each new cast style looks different and meaningful. As
for bad looks, it is not as bad as the C declaration syntax.

Regards,
Biju Thomas
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1999/02/04
Raw View
Biju Thomas wrote:
...
> Was the new cast styles designed to look bad? I thought they were
> designed so that each new cast style looks different and meaningful. As
> for bad looks, it is not as bad as the C declaration syntax.

You're right about them being designed to be different and meaningful.
However, they were also designed with long names to discourage their
unnecessary use. It's too bad that the most dangerous cast, the C-style
cast, couldn't be given a long name, such dangerous_cast<>. As a general
rule (which has exceptions), you should use the implicit casts wherever
they're adequate, and avoid the explicit ones.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/02/04
Raw View
On 04 Feb 99 17:01:22 GMT, James Kuyper <kuyper@wizard.net> wrote:

>You're right about them being designed to be different and meaningful.
>However, they were also designed with long names to discourage their
>unnecessary use. It's too bad that the most dangerous cast, the C-style
>cast, couldn't be given a long name, such dangerous_cast<>. As a general
>rule (which has exceptions), you should use the implicit casts wherever
>they're adequate, and avoid the explicit ones.

How about
   dangerous_C_style_cast<>
This will really get people thinking about what they're doing :).

Your rule that we should use the implicit casts whenever possible is
not good, IMHO.  A C style cast normally is adequate.  In most cases
it means static_cast<>, other times it means const_cast<>, and still
other times it means reinterpret_cast<>.  Sometimes the C style cast
is a combination of two casts -- eg, static_cast<> + const_cast<>.
The bottom line is that it should be easy to transcribe old using C
style casts to new code using C++ style casts.  So why use the C++
casts?  First, they tell clearly which of the casts we want, and this
allows the compiler to do some type checking.  For example, in the
static_cast from Base to Derived, the compiler must know that Derived
is indeed derived from Base.  Second, the C++ casts stand out clearly.
This helps with code maintainance.  I think that C style casts for
pointer and reference types should be deprecated, and am not sure why
the standard doesn't enforce this idea.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1999/02/04
Raw View
Siemel Naran wrote:
...
> Your rule that we should use the implicit casts whenever possible is
> not good, IMHO.  A C style cast normally is adequate.  In most cases

A C style cast is always adequate - that's the problem. It will convert
anything into anything else, whether or not that's what you intended. My
favorite example shows why const_cast<> was such a good idea. I need to
do the following to keep SGI's C compiler (in -fullwarn mode) from
producing inappropriate warnings:

 void func(const int* pi);

 void func2(void)
 {
  int i=3;

  func((const int*)&i); /* Avoids stupid warning message. */
 }

Consider what would happen if 'i' were changed from int to double.
Because of that danger, I don't use the above work-around, with the
result that my const-safe C code is producing lots of inappropriate
warning messages.

Implicit casts have lots of restrictions, which means they'll frequently
fail at compile time if something unexpected is going on - that's what
makes them the preferred kind to use.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1999/02/04
Raw View
Bjarne Stroustrup wrote:
>
> From: James Kuyper <kuyper@wizard.net> writes:
...
>  > unnecessary use. It's too bad that the most dangerous cast, the C-style
>  > cast, couldn't be given a long name, such dangerous_cast<>.
...
> to deprecate the C-style casts. My understanding of the discussion was that
> a large minority felt that deprecating C-style casts would seriously damage
> C/C++ compatibility in the long term. Another large minority wanted to

Yes, that's exactly what I meant by saying that it "couldn't" be done.
C/C++ compatibility was initially absolutely essential to the success of
C++, though I suppose that's less true now. Now, however, we have the
issue of backward compatibility with older C++ code, which imposes the
same constraint.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/02/05
Raw View
In article <36B720A0.B3E348CD@ibm.net>, Biju Thomas <bijuthom@ibm.net>
writes
>> If not, was it because this type of
>> declaration/invoation is considered *bad*, and hence should be made to
>> look bad?  (Kinda like the newer casts.)
>
>I don't think so. There is nothing bad about member templates.
>
>Was the new cast styles designed to look bad? I thought they were
>designed so that each new cast style looks different and meaningful. As
>for bad looks, it is not as bad as the C declaration syntax.

They were designed to be highly visible (easy to grep for) and a little
tedious to write to encourage programmers to think before using.

Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/02/05
Raw View
Biju Thomas <bijuthom@ibm.net> writes:

>Steve Clamage wrote:
>>
>> >>     myType mytmp = MyObj.template myFunc<myType>();
>> >>                          ^^^^^^^^?
>> No, it is required to allow parsing of general expressions like
>>         A . B < C > ( D )
>>
>> If A has a static member B, A.B is its address. The address
>> could be compared with C, and the result compared with D
>> (the parens are redundant).
>>
>> But if B is a template function member of A, we have a
>> function call as in the original code.
>>
>> You can't tell in general whether the '<' is a template
>> bracket or a less-than. To make the determination, you need
>> to know whether myFunc is the name of a template. To know
>> that you need to know what scopes to look in.  To know that,
>> you need to know whether the < is a template bracket.

>Is it that difficult?

>To determine whether B is a template, the compiler has to lookup in the
>scope of the class of the A object.

>Why does the compiler need to know whether B is a template member to
>find out the scope for name lookup?

I got this one wrong. The "template" keyword is only needed in a
template definition when you have something depending on a template
parameter. The situation is the same as needing "typename" to
specify whether a dependant name is a type. Example:

template< class T > void f( T t )
{
    t.g<int>();          // error
    t.template g<int>(); // OK
}

In the first case, it can't be known whether g is a template name,
so it can't be known whether the < is a template bracket or a
less-than. Without the "template" keyword, the rule is that
g is not a template name, and the expression is ill-formed.

There are more details in section 14.2 of the standard.

As with the rule for "typename", the purpose is not to make
life easier for compiler writers, but to make it possible for
compilers to be able to emit better diagnostic messages --
for the benefit of compiler users.

Originally, "typename" and the extra "template" were not required.
Without the help from kewords, it is impossible to parse much
template code and make any decisions about validity. All the
compiler can do is save up the template definitions, and
check for errors at each instantiation.

If an error makes it impossible for the template code to be valid,
you get equivalent error messages on every instantiation. If you
happen not to tickle that error in the template because the function
or class in question wasn't instantiated early in development, you
find out about the error later rather than sooner. You might need
to recompile and regenerate a lot of code. Developers of multi-
million-line applications are sensitive about recompiling the world.

The "typename" and "template" requirement makes it possible for
a compiler to do preliminary parsing and diagnose some things
that could never be valid, and report those errors immediately.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: hursh@sparc.isl.net (hursh)
Date: 1999/02/02
Raw View
Hi,

    I recently spent a few hours trying to find the syntax for what I
had expected to be:

     myType mytmp = MyObj.myFunc<myType>();

The `proper' syntax seems to be:

     myType mytmp = MyObj.template myFunc<myType>();
                          ^^^^^^^^?
  I understand the the syntax error of myType being after the
less-than operator, but putting the template keyword in the invocation
just seems plain ugly.  Is there a more convenient way of doing this
that I missed?  If not, was it because this type of
declaration/invoation is considered *bad*, and hence should be made to
look bad?  (Kinda like the newer casts.)

Regards,
Dan Hursh
hursh@infonet.isl.net
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/02/02
Raw View
On 02 Feb 99 04:09:35 GMT, hursh <hursh@sparc.isl.net> wrote:

>     myType mytmp = MyObj.template myFunc<myType>();
>                          ^^^^^^^^?
>  I understand the the syntax error of myType being after the
>less-than operator, but putting the template keyword in the invocation
>just seems plain ugly.

The 'template' is required to make life easier for the compiler
writer, I think.  It seems to me that '>' could not possibly be
interpreted as less-than because you are required to use '&'
when taking the address of a member function.  Eg,

 MyObj.myFunc<myType>();
    // meaning 1: compare address of MyObj::myfunc with MyType
    // meaning 2: call template member function with argument 'MyType'

But meaning one couldn't possibly be the intended meaning.
Because if wanted meaning one, then we would have to say this,
   &MyObj.myfunc < myType; // note the '&'

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/02/02
Raw View
sbnaran@localhost.localdomain (Siemel Naran) writes:

>On 02 Feb 99 04:09:35 GMT, hursh <hursh@sparc.isl.net> wrote:

>>     myType mytmp = MyObj.template myFunc<myType>();
>>                          ^^^^^^^^?
>>  I understand the the syntax error of myType being after the
>>less-than operator, but putting the template keyword in the invocation
>>just seems plain ugly.

>The 'template' is required to make life easier for the compiler
>writer, I think.

No, it is required to allow parsing of general expressions like
 A . B < C > ( D )

If A has a static member B, A.B is its address. The address
could be compared with C, and the result compared with D
(the parens are redundant).

But if B is a template function member of A, we have a
function call as in the original code.

You can't tell in general whether the '<' is a template
bracket or a less-than. To make the determination, you need
to know whether myFunc is the name of a template. To know
that you need to know what scopes to look in.  To know that,
you need to know whether the < is a template bracket.

The 'template' keyword breaks the circular dependency.

The name lookup rules are complex and context-dependent. The
template keyword is necessary in this case to be able to
parse the code.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: markw65@my-dejanews.com
Date: 1999/02/02
Raw View
In article <slrn7bcvr8.39c.sbnaran@localhost.localdomain>,
  sbnaran@uiuc.edu wrote:
> On 02 Feb 99 04:09:35 GMT, hursh <hursh@sparc.isl.net> wrote:
>
> >     myType mytmp = MyObj.template myFunc<myType>();
> >                          ^^^^^^^^?
> >  I understand the the syntax error of myType being after the
> >less-than operator, but putting the template keyword in the invocation
> >just seems plain ugly.
>
> The 'template' is required to make life easier for the compiler
> writer, I think.  It seems to me that '>' could not possibly be
> interpreted as less-than because you are required to use '&'
> when taking the address of a member function.  Eg,
>
>  MyObj.myFunc<myType>();
>     // meaning 1: compare address of MyObj::myfunc with MyType
>     // meaning 2: call template member function with argument 'MyType'
>
> But meaning one couldn't possibly be the intended meaning.
> Because if wanted meaning one, then we would have to say this,
>    &MyObj.myfunc < myType; // note the '&'
>

What about a specialization where myObj has an int data member called myFunc ?

Mark Williams

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]