问题
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<class Baz> one;
// vs
class Baz;
std::unique_ptr<Baz> two;
回答1:
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…
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:
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:
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
.
来源:https://stackoverflow.com/questions/59609538/difference-between-forward-declaration-in-argument-vs-normal-forward-declarati