Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the C struct hack not work for C++ template declarations?

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?

like image 489
Filipp Avatar asked Mar 03 '23 11:03

Filipp


1 Answers

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.

like image 94
StoryTeller - Unslander Monica Avatar answered Mar 05 '23 01:03

StoryTeller - Unslander Monica