User account creation filtered due to spam.

Bug 9050 - [DR 147] Can't explicitly specialize C++ constructor templates
Summary: [DR 147] Can't explicitly specialize C++ constructor templates
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.2.1
: P3 normal
Target Milestone: 4.5.0
Assignee: Jason Merrill
Keywords: monitored, rejects-valid
: 10832 (view as bug list)
Depends on:
Blocks: 5023 10832 26988
  Show dependency treegraph
Reported: 2002-12-23 19:06 UTC by martin
Modified: 2014-02-16 13:16 UTC (History)
11 users (show)

See Also:
Known to work:
Known to fail: 3.4.3, 4.1.2, 4.3.0, 4.4.0
Last reconfirmed: 2009-11-20 05:17:23


Note You need to log in before you can comment on or make changes to this bug.
Description martin 2002-12-23 19:06:01 UTC
C++ function templates can be explicitly instantiated.
Constructors can be function templates.
So the following should compile 
(and indeed does with icc and Comeau C++)

struct Y
  template <typename T> Y (T);
  template <typename T> void foo (T);

template <> void Y::foo      (bool) { }
template <> void Y::foo<int> (int)  { }

template <>      Y::Y        (bool) { }
template <>      Y::Y<int>   (int)  { }

Explicit instantiation of Y::foo, 
but not Y::Y, is permitted.

g++ gives these errors:

(not only is g++ wrong to give an error,
but the error message below contains the nonsensical
"no member function `._0' declared") `Y' is not a template ISO C++ forbids declaration of `
   type name' with no type abstract declarator `int 
   (Y::)(int)' used as declaration no member function `._0' declared 
   in `Y' syntax error before `{' token

g++ 3.2.1

Linux x86

Compile the provided fragment with "g++ -c"
Comment 1 Kriang Lerdsuwanakij 2002-12-25 00:00:37 UTC
State-Changed-From-To: open->analyzed
State-Changed-Why: Confirmed.
Comment 2 Andrew Pinski 2003-05-25 16:24:07 UTC
it still happens in the mainline (20030525) but it produces different error message:
[omni:~/src/gccPRs] pinskia% g++ error: expected unqualified-id
Comment 3 Volker Reichelt 2003-08-05 15:12:08 UTC
This seems to be related to PR 10832.
Comment 4 Volker Reichelt 2004-01-06 13:07:12 UTC
The error message on mainline now is: error: `Y' is not a template error: expected unqualified-id before "int" error: expected `)' before "int" error: expected `;' before "int"
Comment 5 Andrew Pinski 2004-06-05 18:13:32 UTC
*** Bug 10832 has been marked as a duplicate of this bug. ***
Comment 6 Chris Bowlby 2004-07-22 17:05:13 UTC
Hi All, 

 I've been working on a project for the last month or so and have ran into this 
bug under G++ 2.95.4. The code I have is different from the code above and is 
as follows:


template <class T> class Test {
  T *handle_object;


  Test(T * = NULL);
  Test(const Test<T> &);


  bool operator==(const Test<T> &) const;

class MyTest;
typedef Test<MyTest> MyTestHandle;


template <class T> Test<T>::Test(T* th) {
 this->handle_object = th;

 if (this->handle_object != NULL) {

template <class T> Test<T>::Test(const Test<T> &source) {
 this->handle_object = source.handle_object;

 if (this->handle_object != NULL) {

template <class T> Test<T>::~Test() {
 if (this->handle_object != NULL && this->handle_object->counter != 0) {

 if (this->handle_object != NULL && this->handle_object->counter == 0) {
  delete this->handle_object;
  this->handle_object = NULL;

template <class T> bool Test<T>::operator==(const Test<T> &source) const {
 return (this->handle_object == source->handle_object);

When I left it in this format I got this error:

test/libtest.a(MyBigTest.o): In function `MyBigTest::add(Test<MyTest> const &)':
/usr/local/include/stlport/stl/_construct.h:237: undefined reference to 
`Test<MyTest>::Test(Test<MyTest> const &)'
test/libtest.a(MyBigTest.o): In function `MyBigTest::remove(Test<MyTest> &)':
/usr/local/include/stlport/stl/_list.h:122: undefined reference to 
`Test<MyTest>::operator==(Test<MyTest> const &) const'
test/libtest.a(MyBigTest.o): In function `MyBigTest::remove(Test<MyTest> &)':
/usr/local/include/stlport/stl/_construct.h:360: undefined reference to 
test/libtest.a(MyBigTest.o): In function `_STL::allocator<Test<MyTest> 
r1Zt14Test1Z6MyTest+0x26): undefined reference to `Test<MyTest>::~Test(void)'
*** Error code 1

Research showed that I needed to instantiate my template using:

template void Test<MyTest>();

 in the Test.cpp file so that it can create an instance in the libtest.a file, 
so that when I compile that into my app it would link properly. However, I now 
run into a compiler error (rather then a linking error) like this:

Test.cxx:52: `Test<MyTest>' specified as declarator-id
Test.cxx:52: two or more data types in declaration of `Test<MyTest>'
Test.cxx:52: non-template used as template
Test.cxx:52: confused by earlier errors, bailing out
*** Error code 1

 Which I believe is related to the issue above. I'm building under FreeBSD 4.10-
STABLE. Does anyone have a fix for this yet? or did I do something wrong?
Comment 7 Wolfgang Bangerth 2004-07-22 18:36:35 UTC
The problem in comment #6 has nothing to do with the rest of the 
PR. The syntax to explicitly instantiate the class is just completely 
bogus. It should read 
  template class Test<MyTest>; 
but there are more bugs (specificly: MyTest is only forward declared). 
The original problem of this PR persists as of now. 
Comment 8 Vlad Sharanhovich 2008-02-11 22:19:50 UTC
This bug is present in gcc 3.4.3. Was ever fixed or forgotten forever?
Comment 9 Manuel López-Ibáñez 2008-02-11 23:43:25 UTC
(In reply to comment #8)
> This bug is present in gcc 3.4.3. Was ever fixed or forgotten forever?

manuel@gcc12:~$ ~/132202/build/gcc/cc1plus --version
GNU C++ (GCC) version 4.3.0 20080209 (experimental) [trunk revision 132202] (x86_64-unknown-linux-gnu)
        compiled by GNU C version 4.3.0 20080209 (experimental) [trunk revision 132202], GMP version 4.2.2, MPFR version 2.3.0.
GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096

manuel@gcc12:~$ ~/132202/build/gcc/cc1plus src/pr9050.C
 void Y::foo(T) [with T = bool] void Y::foo(T) [with T = int] Y::Y(T) [with T = bool] Y::Y(T) [with T = bool] Y::Y(T) [with T = bool]
src/pr9050.C: At global scope:
src/pr9050.C:11: error: ‘Y’ is not a template
src/pr9050.C:11: error: expected unqualified-id before ‘int’
src/pr9050.C:11: error: expected `)' before ‘int’

Not fixed.
Comment 10 Manuel López-Ibáñez 2008-10-26 22:01:26 UTC
It seems that the problem is cp_parser_template_id fails to parse Y<int> as a template-id because when it does a lookup it finds that Y is just a non-template class and concludes that Y<int> cannot be a template-id. This in turn makes cp_parser_class_name fail to parse Y<int>, which makes cp_parser_constructor_declarator_p return false.

No idea how this could be fixed...
Comment 11 Jason Merrill 2009-11-21 06:34:11 UTC
Subject: Bug 9050

Author: jason
Date: Sat Nov 21 06:33:56 2009
New Revision: 154403

	PR c++/9050, DR 147, DR 318
	* parser.c (cp_parser_lookup_name): If the name matches the explicit
	class scope, we're naming the constructor.
	(cp_parser_constructor_declarator_p): Just use cp_parser_unqualified_id
	if we have a nested-name-specifier.
	(cp_parser_direct_declarator): Handle getting an overload set as a
	constructor declarator.
	(cp_parser_unqualified_id): Avoid looking up the constructor when
	naming the destructor.
	(cp_parser_diagnose_invalid_type_name): Give good
	diagnostic for improper use of constructor as template.
	* typeck.c (finish_class_member_access_expr): Give good diagnostic
	about calling constructor.

	* error.c (dump_aggr_type): Don't print A::A for injected-class-name.


Comment 12 Jason Merrill 2009-11-21 06:34:31 UTC
Fixed for 4.5.
Comment 13 Johannes Schaub 2012-04-01 14:03:40 UTC
Jason, does not render the explicit specialization ill-formed for C++11TC1? It only allows a simple identifier, and not a template-id.
Comment 14 Johannes Schaub 2012-04-01 14:14:46 UTC
(In reply to comment #13)
> Jason, does
> not render the explicit specialization ill-formed for C++11TC1? It only allows
> a simple identifier, and not a template-id.

FWIW I don't like the resolution of that issue. For a qualified-id, the injected-class-name is an excellent way for us to know when and when not we name a constructor, and it is entirely based on name-lookup rules; I don't see the need to dictate that in clause 12. Only for an unqualified-id, we actually need the rule to know when we declare a constructor. The allowed decl-specifiers in a constructor declaration can be stated separately.
Comment 15 Jason Merrill 2012-04-02 05:41:08 UTC
(In reply to comment #14)

Good point, I've pointed out the problem with the proposed resolution.
Comment 16 Johannes Schaub 2012-04-02 07:43:23 UTC
(In reply to comment #15)
> (In reply to comment #14)
> Good point, I've pointed out the problem with the proposed resolution.

Note that we currently have open. 

Even when 12.1 would have allowed both the injected class name and it followed by template-arguments, the name lookup rules would never allow it to match the second condition because the injected class name would always have been translated to a name denoting the constructor instead of the class.

So ultimately, 12.1 allowing the injected class name followed by template arguments could only be used in an unqualified-id constructor declaration in C++03.
Comment 17 Jackie Rosen 2014-02-16 13:16:06 UTC Comment hidden (spam)