4

C has this fun hack where one name can be used to declare both a type and a function:

struct foo {};
void foo(void);

Now, any time I write foo, the compiler assumes I mean the function unless I prefix it with struct:

foo();  // call void foo(void)
struct foo bar;  // declare variable of type struct foo

This works great in C++ even with namespaces and nesting! But it doesn't work with templates:

template <typename> void bar(void);
template <typename> struct bar {};
// error: conflicting declaration of template struct bar
// previous declaration: template void bar()

Why?

We already get to deal with disambiguators in dependent contexts:

typename foo<A>::b();
foo<A>::template b<C>();

It doesn't seem much of a stretch to apply the regular rules to ambiguous template names of this kind.

Suppose that having the same name is important to me. Could I somehow make this work?

Filipp
  • 1,843
  • 12
  • 26

2 Answers2

4

Why?

The answer is in the body of the question. This works for classes and functions because in C there is a separate namespace for structure tags and function identifiers. If C++ aims to interoperate with C code, it must retain this behavior. One need only look at an API like the stat function taking a struct stat argument to realize why C++ retained the validity of such code. This working with namespaces is simply inline with C code residing in the global namespace (so ::stat and struct ::stat should continue to work when needed).

However, in C++ the identifiers of class tags share a "namespace" with regular identifiers. And so the validity of this "hack" is achieved with a special case in the C++ specification that simply hides classes when they would conflict.

[basic.scope.hiding]

2 A class name or enumeration name can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.

It doesn't matter if the designers of C++ thought it was a good or bad idea. There is legacy code that should continue to be accepted as valid by C++ compilers for ease of inter-operating with certain systems.

But there is no legacy code dealing with templates that requires the same behavior. Templates are an entirely C++ construct (not related to C at all). And such, the language design doesn't have an outside constraint to add more special cases for template names too. And so it doesn't.

Suppose that having the same name is important to me. Could I somehow make this work?

No way to make it work comes to mind.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
3

The wording is in temp.pre-7:

A class template shall not have the same name as any other template, class, function, variable, enumeration, enumerator, namespace, or type in the same scope ([basic.scope]), except as specified in [temp.class.spec]...

None of the points in temp.class.spec conflict with this example.

So, as it stands, you can't have the same name for a class template and a function template.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • Did the committee consider removing this restriction as a way to implement CTAD? – Filipp May 10 '20 at 02:50
  • I'm not sure what you mean; we already have CTAD. Also, I don't see this as a restriction, but as a feature. Ideally, I would like to not be able to do this even for non-templates. – cigien May 10 '20 at 02:57
  • We have CTAD today, but between 14 and 17 this was an open question. Is `std::pair a(1, 2);` that much better than `auto a = std::pair(1, 2);` where the latter use is a function that works like `std::make_pair`? – Filipp May 10 '20 at 14:28