在参数中的前向声明与“正常”前向声明之间的区别

huangapple go评论83阅读模式
英文:

Difference between forward declaration in argument vs "normal" forward declaration

问题

以下是翻译好的部分:

  • 在(模板)参数中使用精细化类型说明符的前向声明与“正常”的前向声明之间是否有区别 - 如果有的话 - 是什么?
void foo(struct bar *);

// 与

struct bar;
void foo(bar *);

// ------ 还有 -------

std::unique_ptr<class Baz> one;

// 与

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

What is - if any - the difference between a forward declaration in a (template) argument (using an elaborated type specifier) and a "normal" forward declaration?

void foo(struct bar *);

// vs

struct bar;
void foo(bar *);

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

std::unique_ptr&lt;class Baz&gt; one;

// vs

class Baz;
std::unique_ptr&lt;Baz&gt; two;

答案1

得分: 4

"Forward declaration"是一种口头用语,用来指代某些声明的一种常见实际用法。就C++标准而言,并不存在所谓的"forward declaration"。只有声明存在。

考虑到这一点,我认为以下两种声明对名称bar的影响是相同的:

void foo(struct bar *);

struct bar;

只要没有先前的声明已经引入了bar这个名称,这两个声明最终都会引入结构体bar的名称。

在C++17中,相关的段落似乎是basic.lookup.elab/2(我强调了一部分内容):

如果elaborated-type-specifierclass-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

英文:

Let's begin by noting that "forward declaration" is a colloquialism used to refer to a certain common practical use of certain kinds of declarations. There is no such thing as a forward declaration as far as the C++ standard is concerned. There are just declarations.

With that in mind, I believe that there is no difference between

void foo(struct bar *);

and

struct bar;

as far as their effect on the name bar is concerned. Both declarations end up introducing the name of the struct bar if there is no previous declaration that already did so.

The relevant paragraph in C++17 would seem to be [basic.lookup.elab]/2 (emphasis mine):

> If the elaborated-type-specifier is introduced by the class-key and this lookup does not find a previously declared type-name, or […] the elaborated-type-specifier is a declaration that introduces the class-name as described in [basic.scope.pdecl].

If an elaborated-type-specifier that doesn't contain a nested-name-specifier is encountered, unqualified name lookup is performed to see if the name already names a corresponding type. If no previously declared name is found, then the elaborated-type-specifier becomes a declaration of the class type of that name&hellip;

As pointed out by geza, the one way in which there can be a difference has to do with the scope into which the name is introduced. While

struct bar;

always introduces the name into the scope in which the declaration appears, an elaborated-type-specifier appearing as part of any other kind of declaration will introduce the name into the closest enclosing namespace [basic.scope.pdecl]/7.

答案2

得分: 3

以下是翻译好的部分:

"差异可能在声明引入的作用域方面。在精细化的类型说明符的情况下,声明是在最接近的命名空间中引入的,这可能会产生差异。

例如:

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

在这里,Bar 在全局命名空间中声明,而不是在 Foo 中。"

英文:

The difference can be the scope the declaration introduced. In case of elaborated type specifier, the declaration is introduced in the closest namespace, and this can make a difference.

For example:

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

Here, Bar is declared in the global namespace, not in Foo.

答案3

得分: 2

如果你不提前声明 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 的指针。

英文:

If you don't declare struct bar; beforehand, then struct bar might refer to type name declared in an outer scope (which might come from a completely different library). For example:

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

^ Here the parameter of foo is pointer to the class bar in global scope.

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

^ Here the parameter of foo is pointer to ns::bar.

huangapple
  • 本文由 发表于 2020年1月6日 17:25:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/59609538.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定