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>’).
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
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.
(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; }
.
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
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."
(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?
Jason, could you have a look at the code in comment 3 and say whether the lookup result is correct? thanks
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.
*** Bug 55668 has been marked as a duplicate of this bug. ***
As I indicated in PR 55668, this has been broken since at least 4.1.2.
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.
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.
*** Bug 56629 has been marked as a duplicate of this bug. ***
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.
. *** This bug has been marked as a duplicate of bug 54769 ***