c++ 参数中的前向声明与“普通”前向声明之间的区别

sh7euo9m  于 2024-01-09  发布在  其他
关注(0)|答案(3)|浏览(144)

在(模板)参数中的前向声明(使用elaborated type specifier)和“普通”前向声明之间有什么区别?

void foo(struct bar *);

// vs

struct bar;
void foo(bar *);

// ------ and also -------

std::unique_ptr<class Baz> one;

// vs

class Baz;
std::unique_ptr<Baz> two;

字符串

vxqlmq5t

vxqlmq5t1#

让我们开始注意到“前向声明”是一种口语,用来指某些类型的声明的某种常见的实际用途。就C++标准而言,没有前向声明这样的东西。只有声明。
考虑到这一点,我认为,

void foo(struct bar *);

字符串

struct bar;


就它们对名称bar的影响而言。如果之前没有这样做的声明,那么这两个声明最终都会引入结构bar的名称。
C++17中的相关段落似乎是[basic.lookup.elab]/2(重点是我的):
如果 elaborated-type-specifier 是由 class-key 引入的,并且这个查找没有找到之前声明的 type-name,或者[...]**,则 elaborated-type-specifier 是一个引入 *class-name * 的声明,如[basic.scope.pdecl]中所述。
如果遇到不包含 nested-name-specifierelaborated-type-specifier,则执行非限定名称查找以查看该名称是否已经命名了相应的类型。如果没有找到以前声明的名称,则 elaborated-type-specifier 成为该名称的类类型的声明.
正如geza所指出的那样,可能存在差异的一种方式与引入名称的范围有关。

struct bar;


总是将名称引入声明出现的作用域中,作为任何其他类型声明的一部分出现的 elaborated-type-specifier 将名称引入最近的封闭命名空间[basic.scope.pdecl]/7。

fdbelqdn

fdbelqdn2#

不同之处可能是声明引入的作用域。在精心设计的类型说明符的情况下,声明被引入到最近的命名空间中,这可能会造成差异。
举例来说:

struct Foo {
      void fn(struct Bar *);
};

字符串
在这里,Bar是在全局命名空间中声明的,而不是在Foo中声明的。

50pmv0ei

50pmv0ei3#

如果你没有事先声明struct bar;,那么struct bar可能会引用在外部作用域中声明的类型名(可能来自一个完全不同的库)。例如:

class bar {};
// ...
namespace ns {
    void foo(struct bar *);
}

字符串
^这里foo的参数是指向全局作用域中的类bar的指针。

class bar {};
// ...
namespace ns {
    struct bar;
    void foo(bar *);
}


^这里foo的参数是指向ns::bar的指针。

相关问题