为什么 C struct hack 不适用于 C++ 模板声明?
Why does the C struct hack not work for C++ template declarations?
C 有一个有趣的 hack,其中可以使用一个名称来声明类型和函数:
struct foo {};
void foo(void);
现在,每当我写 foo
时,编译器都假定我指的是函数,除非我在它前面加上 struct
:
foo(); // call void foo(void)
struct foo bar; // declare variable of type struct foo
这在 C++ 中非常有效,即使有命名空间和嵌套!
但它不适用于模板:
template <typename> void bar(void);
template <typename> struct bar {};
// error: conflicting declaration of template struct bar
// previous declaration: template void bar()
为什么?
我们已经开始处理依赖上下文中的消歧器:
typename foo<A>::b();
foo<A>::template b<C>();
将常规规则应用于这种模棱两可的模板名称似乎并不难。
假设同名对我很重要。我能以某种方式使它工作吗?
Why?
答案在问题正文中。这适用于 classes 和函数,因为在 C 中有一个单独的命名空间用于结构标记和函数标识符。如果 C++ 旨在与 C 代码进行互操作,则它必须保留此行为。人们只需要看一下 API 就像 stat
function 接受一个 struct stat
参数就可以理解为什么 C++ 保留了这种代码的有效性。这种使用名称空间的方式只是与驻留在全局名称空间中的 C 代码内联(因此 ::stat
和 struct ::stat
应该在需要时继续工作)。
但是,在 C++ 中,class 标记的标识符与常规标识符共享一个 "namespace"。因此,这个 "hack" 的有效性是通过 C++ 规范中的一个特殊情况实现的,它在它们会发生冲突时简单地隐藏 classes。
[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.
C++ 的设计者认为这是好主意还是坏主意并不重要。遗留代码应继续被 C++ 编译器接受为有效代码,以便于与某些系统进行互操作。
但是没有遗留代码处理需要相同行为的模板。模板完全是 C++ 构造(与 C 完全无关)。因此,语言设计也没有外部约束来为模板名称添加更多特殊情况。所以它没有。
Suppose that having the same name is important to me. Could I somehow make this work?
没有办法让它发挥作用。
措辞在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]...
temp.class.spec 中的 None 点与此示例冲突。
因此,就目前而言,class 模板和函数模板不能具有相同的名称。
C 有一个有趣的 hack,其中可以使用一个名称来声明类型和函数:
struct foo {};
void foo(void);
现在,每当我写 foo
时,编译器都假定我指的是函数,除非我在它前面加上 struct
:
foo(); // call void foo(void)
struct foo bar; // declare variable of type struct foo
这在 C++ 中非常有效,即使有命名空间和嵌套! 但它不适用于模板:
template <typename> void bar(void);
template <typename> struct bar {};
// error: conflicting declaration of template struct bar
// previous declaration: template void bar()
为什么?
我们已经开始处理依赖上下文中的消歧器:
typename foo<A>::b();
foo<A>::template b<C>();
将常规规则应用于这种模棱两可的模板名称似乎并不难。
假设同名对我很重要。我能以某种方式使它工作吗?
Why?
答案在问题正文中。这适用于 classes 和函数,因为在 C 中有一个单独的命名空间用于结构标记和函数标识符。如果 C++ 旨在与 C 代码进行互操作,则它必须保留此行为。人们只需要看一下 API 就像 stat
function 接受一个 struct stat
参数就可以理解为什么 C++ 保留了这种代码的有效性。这种使用名称空间的方式只是与驻留在全局名称空间中的 C 代码内联(因此 ::stat
和 struct ::stat
应该在需要时继续工作)。
但是,在 C++ 中,class 标记的标识符与常规标识符共享一个 "namespace"。因此,这个 "hack" 的有效性是通过 C++ 规范中的一个特殊情况实现的,它在它们会发生冲突时简单地隐藏 classes。
[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.
C++ 的设计者认为这是好主意还是坏主意并不重要。遗留代码应继续被 C++ 编译器接受为有效代码,以便于与某些系统进行互操作。
但是没有遗留代码处理需要相同行为的模板。模板完全是 C++ 构造(与 C 完全无关)。因此,语言设计也没有外部约束来为模板名称添加更多特殊情况。所以它没有。
Suppose that having the same name is important to me. Could I somehow make this work?
没有办法让它发挥作用。
措辞在temp.pre-7:
temp.class.spec 中的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 点与此示例冲突。
因此,就目前而言,class 模板和函数模板不能具有相同的名称。