Bug 55576 - Fails to compile a call to template member function
Summary: Fails to compile a call to template member function
Status: RESOLVED DUPLICATE of bug 54769
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.7.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 55668 56629 (view as bug list)
Depends on:
Blocks:
 
Reported: 2012-12-03 15:26 UTC by Antony Polukhin
Modified: 2017-06-28 01:52 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-12-06 00:00:00


Attachments
Output of `gcc -v -save-temps -Wall -Wextra main.cpp` (914 bytes, text/plain)
2012-12-03 15:26 UTC, Antony Polukhin
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Antony Polukhin 2012-12-03 15:26:20 UTC
Created attachment 28860 [details]
Output of `gcc -v -save-temps -Wall -Wextra main.cpp`

When compiling following code:

struct factory {
 template <typename T>
 void * apply(void * address)
 {
  return new (address) T;
 }
};

template <typename T>
struct apply {
 template <typename FactoryT>
 void* operator()(FactoryT const& f, void * address) {
  return f.template apply<T>(address);
 }
};

int main() {
 int place;
 apply<int>()(factory(), &place);
 return 0;
}


Tries to instantiate structure `apply` instead of calling a `factory` member function `apply` (prints error: invalid use of ‘struct apply<T>’).
Comment 1 Jonathan Wakely 2012-12-03 16:00:35 UTC
I don't think this is a G++ bug, there are three problems with this code:

1) You need to #include <new> to use placement new
2) factory::apply is non-const but the parameter 'f' is const
3) f.template apply<T> finds the current instantiation, ::apply<T>, rather than the member function you are trying to call, use f.FactoryT::template apply<T> instead
Comment 2 Paolo Carlini 2012-12-03 16:08:31 UTC
Indeed. I also want to add that neither Icc 13, nor Oracle Solaris Studio 12.3, nor Clang 3.0 accept it, whereas the code adjusted per Jon's points compiles just fine with all of them.
Comment 3 Antony Polukhin 2012-12-04 07:12:12 UTC
(In reply to comment #1)
> I don't think this is a G++ bug, there are three problems with this code:
> 
> 1) You need to #include <new> to use placement new
> 2) factory::apply is non-const but the parameter 'f' is const

Fixed

> 3) f.template apply<T> finds the current instantiation, ::apply<T>, rather than
> the member function you are trying to call, use f.FactoryT::template apply<T>
> instead

That is the point. `f.template apply<T>(address);` is accepted by some compilers without `FactoryT::`

Fixed version:

struct factory {
 template <typename T>
 void * apply(void * address) const {
  return 0;
 }
};

template <typename T>
struct apply {
 template <typename FactoryT>
 void* operator()(FactoryT const& f, void * address) const {
  return f.template apply<T>(address); // error: invalid use of ‘struct apply<T>’ why???
 }
};

int main() {
 int place;
 apply<int>()(factory(), &place);
 return 0;
}
Comment 4 Paolo Carlini 2012-12-04 09:37:44 UTC
.
Comment 5 Marc Glisse 2012-12-04 10:47:38 UTC
For the example of comment #3, clang compiles it happily, and comeau gives this message:

"ComeauTest.c", line 12: error: type name is not allowed
    return f.template apply<T>(address);
                      ^

"ComeauTest.c", line 12: warning: ambiguous class member reference -- function
          template "factory::apply" (declared at line 3) used in preference to
          type "apply<T>::apply [with T=int]" (declared at line 9)
    return f.template apply<T>(address);
                      ^
          detected during instantiation of "void *apply<T>::operator()(const
                    FactoryT &, void *) const [with T=int, FactoryT=factory]"
                    at line 18
Comment 6 Jonathan Wakely 2012-12-04 11:04:45 UTC
I've been trying to find the relevant text in the standard but I'm not entirely sure where this is covered. Possibly [temp.local] paras 3-5, including

"The injected-class-name of a class template or class template specialization can be used either as a template-name or a type-name wherever it is in scope."
Comment 7 Antony Polukhin 2012-12-06 14:39:39 UTC
(In reply to comment #6)
> "The injected-class-name of a class template or class template specialization
> can be used either as a template-name or a type-name wherever it is in scope."

So, shall we reopen this ticket?
Comment 8 Jonathan Wakely 2012-12-06 15:46:59 UTC
Jason, could you have a look at the code in comment 3 and say whether the lookup result is correct? thanks
Comment 9 Jason Merrill 2012-12-06 16:33:09 UTC
3.4.5 seems clear on this point:

The identifier is first looked up in the class of the object expression. If the identifier is not found, it is then looked up in the context of the entire postfix-expression and shall name a class template.

So the testcase in comment 3 is valid.
Comment 10 Tudor Bosman 2012-12-13 18:01:42 UTC
*** Bug 55668 has been marked as a duplicate of this bug. ***
Comment 11 Tudor Bosman 2012-12-13 18:03:35 UTC
As I indicated in PR 55668, this has been broken since at least 4.1.2.
Comment 12 David Krauss 2013-02-25 14:06:30 UTC
Note, this is due to a C++11 change. Under C++03 there were additional rules in 3.4.5/1 rendering the code ill-formed. So it's not a coincidence this just popped up recently.

Also, Clang compiles the example from comment 3.
Comment 13 Daniel Frey 2013-02-25 16:20:20 UTC
Since it wasn't pointed out explicitly: The behaviour should depend on the presence or absence of -std=c++0x/c++11/gnu++0x/gnu++11. The OPs example wasn't compiled without any of these options, so it should be an error and GCC is correct. With C++11 enabled, GCC's behaviour should be changed.
Comment 14 Paolo Carlini 2013-03-16 09:45:38 UTC
*** Bug 56629 has been marked as a duplicate of this bug. ***
Comment 15 Jason Merrill 2016-07-18 16:06:48 UTC
Looking at the standard again, I notice

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 object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template.

This suggests that the 'template' keyword specifies that the following name is a *member* template, and that we shouldn't look in the current scope at all.

It seems like the main change needed is passing template_keyword_p into cp_parser_nested_name_specifier_opt.
Comment 16 Jason Merrill 2017-06-28 01:52:13 UTC
.

*** This bug has been marked as a duplicate of bug 54769 ***