Topic: After dependent name lookup: Changing parse tree in context of a template-name?


Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Wed, 7 Apr 2010 15:16:30 CST
Raw View
On 7 Apr, 00:11, "Johannes Schaub (litb)" <schaub-johan...@web.de>
wrote:
> Comeau sees to parse the template body assuming that "T::Bar<1>(0)" is
> using op<, but then when dependent name lookup finishes, decides to take
> "T::Bar<1>" as a template-id. It looks to me that 14.2/3 can be interpreted
> in that manner. (I don't think that it intends to be interpreted that way,
> though and some committee member told me so too).

Probably, Comeau C++ performs trial parsing of a template definition
and then reparses the definition of the respective template
specialization considering template arguments and ignoring the rules
quoted in my previous message. On the first step it considers T::Bar
as an expression, but on the second step it wrongfully considers
T::Bar and T::Bar<1> as template and simple-type-specifier
respectively.

According to the rules (C++03 or N3092), we must use "template" and
"typename" keywords here:

   struct Foo {
       template <int>
           struct Bar { Bar(int) {} };
   };

   template <class T>
       void foo() {
           typename T::template Bar < 1 > (0);
   }

   int main() {
       foo<Foo>();
   }

Otherwise the program is ill-formed, and the diagnostic is required.
Moreover, we must use "template" keyword even if template-id is not
formed:

   struct Foo {
       template <class T>
           static void bar(T) { }
   };

   template <class T>
       void foo() {
           T::template bar(0); // "template" is necessary
   }

   int main() {
       foo<Foo>();
   }

Comeau C++ wrongfully rejects this code.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Mon, 5 Apr 2010 19:20:45 CST
Raw View
On 23 Mar, 13:35, "Johannes Schaub (litb)" <schaub-johan...@web.de>
wrote:
> A question arose in a thread of comp.lang.c++.moderated whether the
> following is well-formed or ill-formed:
>
> struct Foo {
>  template <int I>
>  static void bar(char(*)[I]) { }
>
> };
>
> template <class T>
> void foo() {
>    typedef char one[1];
>    !(void(*)(one*))T::bar < -1 > (0);
>
> }
>
> int main(){
>  foo<Foo>();
>
> }
>
> The comeau compiler (and apparently the intel compiler too) accepts that
> code, apparently treating "T::bar<-1>" as a template-id instead of an
> expression with two relational operators. So comeau/intel fails to compile
> because of SFINAE making "bar" non-viable. Other compilers compile this
> fine, because the cast deduces "I" to 1, and we end up comparing the
result
> converted to bool to "-1".

IMO, the behavior of Comeau C++ and these "other compilers" is wrong.

C++03 [temp.names]/4:
"When the name of a member template specialization appears after . or -
> in a postfix-expression, or after nested-name-specifier in a
qualified-id, and the postfix-expression or qualified-id explicitly
depends on a template-parameter (14.6.2), the member template name
must be prefixed by the keyword template."

C++03 [temp.res]/3:
"A qualified-id that refers to a type and in which the nested-name-
specifier depends on a template-parameter (14.6.2) shall be prefixed
by the keyword typename to indicate that the qualified-id denotes a
type, forming an elaborated-type-specifier (7.1.5.3)."

N3092 [temp.names]/4:
When the name of a member template specialization appears after . or -
> in a postfix-expression, or after a nested-name-specifier in a
qualified-id, and the postfix-expression or qualified-id explicitly
depends on a template-parameter (14.6.2) but does not refer to a
member of the current instantiation (14.6.2.1), the member template
name must be prefixed by the keyword template.

N3092 [temp.res]/3:
"When a qualified-id is intended to refer to a type that is not a
member of the current instantiation (14.6.2.1) and its nested-name-
specifier depends on a template-parameter (14.6.2), it shall be
prefixed by the keyword typename, forming a typename-specifier."

Comeau C++ frequently ignores these restrictions:

   struct Foo {
       template <int>
           struct Bar { Bar(int) {} };
   };

   template <class T>
       void foo() {
           T::Bar < 1 > (0);
   }

   int main() {
       foo<Foo>(); // must be diagnosed
   }


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Tue, 6 Apr 2010 14:11:02 CST
Raw View
Nikolay Ivchenkov wrote:

> On 23 Mar, 13:35, "Johannes Schaub (litb)" <schaub-johan...@web.de>
> wrote:
>> A question arose in a thread of comp.lang.c++.moderated whether the
>> following is well-formed or ill-formed:
>>
>> struct Foo {
>>  template <int I>
>>  static void bar(char(*)[I]) { }
>>
>> };
>>
>> template <class T>
>> void foo() {
>>    typedef char one[1];
>>    !(void(*)(one*))T::bar < -1 > (0);
>>
>> }
>>
>> int main(){
>>  foo<Foo>();
>>
>> }
>>
>> The comeau compiler (and apparently the intel compiler too) accepts that
>> code, apparently treating "T::bar<-1>" as a template-id instead of an
>> expression with two relational operators. So comeau/intel fails to
>> compile because of SFINAE making "bar" non-viable. Other compilers
>> compile this fine, because the cast deduces "I" to 1, and we end up
>> comparing the
> result
>> converted to bool to "-1".
>
> IMO, the behavior of Comeau C++ and these "other compilers" is wrong.
>
> C++03 [temp.names]/4:
> "When the name of a member template specialization appears after . or -
>> in a postfix-expression, or after nested-name-specifier in a
> qualified-id, and the postfix-expression or qualified-id explicitly
> depends on a template-parameter (14.6.2), the member template name
> must be prefixed by the keyword template."
>
> C++03 [temp.res]/3:
> "A qualified-id that refers to a type and in which the nested-name-
> specifier depends on a template-parameter (14.6.2) shall be prefixed
> by the keyword typename to indicate that the qualified-id denotes a
> type, forming an elaborated-type-specifier (7.1.5.3)."
>
> N3092 [temp.names]/4:
> When the name of a member template specialization appears after . or -
>> in a postfix-expression, or after a nested-name-specifier in a
> qualified-id, and the postfix-expression or qualified-id explicitly
> depends on a template-parameter (14.6.2) but does not refer to a
> member of the current instantiation (14.6.2.1), the member template
> name must be prefixed by the keyword template.
>
> N3092 [temp.res]/3:
> "When a qualified-id is intended to refer to a type that is not a
> member of the current instantiation (14.6.2.1) and its nested-name-
> specifier depends on a template-parameter (14.6.2), it shall be
> prefixed by the keyword typename, forming a typename-specifier."
>
> Comeau C++ frequently ignores these restrictions:
>
>    struct Foo {
>        template <int>
>            struct Bar { Bar(int) {} };
>    };
>
>    template <class T>
>        void foo() {
>            T::Bar < 1 > (0);
>    }
>
>    int main() {
>        foo<Foo>(); // must be diagnosed
>    }
>
>

I'm wondering whether this is because of

14.2/3
"After name lookup (3.4) finds that a name is a template-name, if this name
is followed by a <, the < is always taken as the beginning of a template-
argument-list and never as a name followed by the less-than operator. "

? Comeau sees to parse the template body assuming that "T::Bar<1>(0)" is
using op<, but then when dependent name lookup finishes, decides to take
"T::Bar<1>" as a template-id. It looks to me that 14.2/3 can be interpreted
in that manner. (I don't think that it intends to be interpreted that way,
though and some committee member told me so too).

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Tue, 23 Mar 2010 03:35:32 CST
Raw View
A question arose in a thread of comp.lang.c++.moderated whether the
following is well-formed or ill-formed:

struct Foo {
 template <int I>
 static void bar(char(*)[I]) { }
};

template <class T>
void foo() {
   typedef char one[1];
   !(void(*)(one*))T::bar < -1 > (0);
}

int main(){
 foo<Foo>();
}

The comeau compiler (and apparently the intel compiler too) accepts that
code, apparently treating "T::bar<-1>" as a template-id instead of an
expression with two relational operators. So comeau/intel fails to compile
because of SFINAE making "bar" non-viable. Other compilers compile this
fine, because the cast deduces "I" to 1, and we end up comparing the result
converted to bool to "-1".

Why does comeau behave the way it behaves? Any EDG guys in here? Thanks!

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]