Discussion:
Templates and greater than / less than ambiguity
(too old to reply)
c***@gmail.com
2008-08-05 05:11:21 UTC
Permalink
Hi all,

I've got a problem which appears to be related to the ambiguity
between
template <> brackets and greater and less than symbols... Here's a
snippet of
code which I'm having trouble with:

--------------------------------------------------
struct Tag
{
typedef int type;
};

struct A
{
template<typename TagT>
typename TagT::type find(typename TagT::type i)
{
return i;
}
};

template<typename T>
int foo()
{
int i = 0;
T t;
// The following doesn't compile but is well-formed if t.find is a
template
// member of T, and Tag is a type.
i = t.find<Tag>(1);
// While the below should be functionally equivalent
//i = static_cast<A>(t).find<Tag>(42);

return i;
}

int main()
{
int i = foo<A>();
return 0;
}

--------------------------------------------------

This is just a cut-down toy version, but it shows the main thing I'm
having
problems with. What I want is to be able to use an expression like

t.find<Tag>(1);

where t is a template type, Tag is some tag struct, and find is a
template
member function. When I try to compile the above example, g++ gives
an error
like

main.cpp: In function 'int foo()':
main.cpp:22: error: expected primary-expression before '>' token

The error goes away if I write an explicit cast:

static_cast<A>(t).find<Tag>(1);

I can see how the expression could be ambiguous, since the following
compiles
fine:

--------------------------------------------------
struct B
{
static const int find = 1;
};

int bar()
{
B b;
int Tag = 1;
int j = b.find < Tag > (1);
return j;
}
--------------------------------------------------

- in this case Tag and b.find are variables, but the exact same syntax
is
used.

Am I doing something wrong here? Is this somehow forbidden by the C++
spec?
Otherwise I guess it's a compiler error...

Any help appreciated, thanks for your time.
~Chris F.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Pavel Minaev
2008-08-05 16:27:45 UTC
Permalink
Post by c***@gmail.com
I've got a problem which appears to be related to the ambiguity
between
template <> brackets and greater and less than symbols... Here's a
snippet of
--------------------------------------------------
struct Tag
{
typedef int type;
};
struct A
{
template<typename TagT>
typename TagT::type find(typename TagT::type i)
{
return i;
}
};
template<typename T>
int foo()
{
int i = 0;
T t;
// The following doesn't compile but is well-formed if t.find is a
template
// member of T, and Tag is a type.
i = t.find<Tag>(1);
As you've correctly spotted, it is ambiguous because the compiler
cannot tell in advance what T::find will be - a template, or something
with operator<.
You should use the following syntax to explicitly tell the compiler
that T::find is a function template:

i = t.template find<Tag>(1);
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Alberto Ganesh Barbati
2008-08-05 16:30:38 UTC
Permalink
Post by c***@gmail.com
template<typename T>
int foo()
{
int i = 0;
T t;
// The following doesn't compile but is well-formed if t.find is a
template
// member of T, and Tag is a type.
i = t.find<Tag>(1);
This is a FAQ.

The code is *not* well-formed, because "find" is *not* interpreted as
the name of a template. You must write:

i = t.template find<Tag>(1);

This is because the syntactic disambiguation must happen at the point of
declaration of the template, where the type T is still unknown. It
cannot be deferred to point of instantiation, where T is substituted
with the actual type that happens to have a member template named "find".

HTH,

Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
c***@gmail.com
2008-08-06 14:21:36 UTC
Permalink
Post by Alberto Ganesh Barbati
Post by c***@gmail.com
template<typename T>
int foo()
{
int i = 0;
T t;
// The following doesn't compile but is well-formed if
// t.find is a template member of T, and Tag is a type.
i = t.find<Tag>(1);
This is a FAQ.
Ah, indeed :-( For anyone reading this thread in the future,
further details may be found in question 6 of the C++ template
FAQ, "Why do I need to add "template" and "typename" in the
bodies of template definitions?":

http://womble.decadentplace.org.uk/c++/template-faq.html

I find the example given in faq 6 a little opaque, but
nevertheless it is there. Usage of the typename keyword for
disabiguation is covered in the C++ FAQ lite, but I couldn't
find a mention of this use of the template keyword there.
Post by Alberto Ganesh Barbati
The code is *not* well-formed, because "find" is *not*
interpreted as the name of a template.
Oops, as others have also pointed out (thanks), my original code
is not well-formed. The comment was intended as an off-hand
remark "should be ok" rather than an actual claim of precise
well-formedness...
Post by Alberto Ganesh Barbati
i = t.template find<Tag>(1);
This is because the syntactic disambiguation must happen at the
point of declaration of the template, where the type T is still
unknown. It cannot be deferred to point of instantiation, where
T is substituted with the actual type that happens to have a
member template named "find".
This makes sense, thanks.

Many thanks to all who replied, and apologies for the poor line
wrapping in my first message, I *hope* that is now fixed.
~Chris F.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jiang
2008-08-05 16:30:27 UTC
Permalink
On Aug 5, 2:11 pm, ***@gmail.com wrote:

[...]
Post by c***@gmail.com
where t is a template type, Tag is some tag struct, and find is a
template
member function. When I try to compile the above example, g++ gives
an error
like
main.cpp:22: error: expected primary-expression before '>' token
static_cast<A>(t).find<Tag>(1);
The above code is ill-formed. It should be

i = t.template find<Tag>(1);

Add template keyword to tell the compiler here you are doing
template programming. Otherwise the compiler will treat "<"
as "less than" :

In 14.2/p4, we have

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.
Otherwise the name is assumed to name a non-template.

HTH

Jiang
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
c***@gmail.com
2008-08-06 14:23:08 UTC
Permalink
Post by Jiang
Add template keyword to tell the compiler here you are doing
template programming. Otherwise the compiler will treat "<"
In 14.2/p4, we have
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.
Otherwise the name is assumed to name a non-template.
Ok, so if I'm reading this standardese correctly:

In my case, find<Tag>
* is a member template specialization
* appears after . in a postfix expression

In addition,
* the postfix expression explicitly depends on a template
parameter, Tag.

Therefore, without including the keyword template, t.find is
assumed to be a non-template and the expression fails to parse.
This is because Tag is a type rather than a variable and doesn't
make sense in a less than comparison.

Thanks again,
~Chris F.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Yechezkel Mett
2008-08-07 15:58:25 UTC
Permalink
Post by c***@gmail.com
Post by Jiang
In 14.2/p4, we have
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.
Otherwise the name is assumed to name a non-template.
In my case, find<Tag>
* is a member template specialization
* appears after . in a postfix expression
In addition,
* the postfix expression explicitly depends on a template
parameter, Tag.
The postfix expression depends on the template parameter T, not Tag.

Yechezkel Mett
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Thomas Maeder
2008-08-05 17:07:08 UTC
Permalink
Post by c***@gmail.com
--------------------------------------------------
struct Tag
{
typedef int type;
};
struct A
{
template<typename TagT>
typename TagT::type find(typename TagT::type i)
{
return i;
}
};
template<typename T>
int foo()
{
int i = 0;
T t;
// The following doesn't compile but is well-formed if t.find is a
template
It's only well-formed if t.find is a template and if you explicitly
tell the compiler about it.
Post by c***@gmail.com
// member of T, and Tag is a type.
i = t.find<Tag>(1);
i = t.template find<Tag>(1);

Otherwise, the compiler has to assume that "find" does not name a
template.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Markus Moll
2008-08-05 17:28:25 UTC
Permalink
Hi
Post by c***@gmail.com
What I want is to be able to use an expression like
t.find<Tag>(1);
where t is a template type, Tag is some tag struct, and find is a
template member function. When I try to compile the above example, g++
gives an error like
main.cpp:22: error: expected primary-expression before '>' token
[...]
Post by c***@gmail.com
Am I doing something wrong here?
Yes.
Post by c***@gmail.com
Is this somehow forbidden by the C++ spec?
Well, not exactly. The problem is that the compiler does not know that
t.find names a template, as it doesn't know what type t has. Just like with
typename, you have to tell the compiler that t.find is not an object, but
the name of a template:

t.template find<Tag>(1);

Markus
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mathias Gaunard
2008-08-05 17:28:24 UTC
Permalink
Post by c***@gmail.com
template<typename T>
int foo()
{
int i = 0;
T t;
// The following doesn't compile but is well-formed if t.find is a
template
// member of T, and Tag is a type.
i = t.find<Tag>(1);
i = t.template find<Tag>(1);

Just like you need to use the keyword "typename" to say a static
member of a template-dependent type is a typename and not a static
variable, you need to use "template" to say a member function of a
template-dependent object is a template member function and not a
regular member function.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Loading...