A declaration (Clause [dcl.dcl]) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations. If so, the declaration specifies the interpretation and attributes of these names. A declaration may also have effects including:
a static assertion (Clause [dcl.dcl]),
controlling template instantiation ([temp.explicit]),
guiding template argument deduction for constructors ([temp.deduct.guide]),
use of attributes (Clause [dcl.dcl]), and
nothing (in the case of an empty-declaration).
A declaration is a definition unless
it declares a function without specifying the function's body ([dcl.fct.def]),
it contains the extern specifier ([dcl.stc]) or a linkage-specification26 ([dcl.link]) and neither an initializer nor a function-body,
it declares a non-inline static data member in a class definition ([class.mem], [class.static]),
it declares a static data member outside a class definition and the variable was defined within the class with the constexpr specifier (this usage is deprecated; see [depr.static_constexpr]),
it is a class name declaration ([class.name]),
it is an opaque-enum-declaration ([dcl.enum]),
it is a template-parameter ([temp.param]),
it is a parameter-declaration ([dcl.fct]) in a function declarator that is not the declarator of a function-definition,
it is a typedef declaration ([dcl.typedef]),
it is an alias-declaration ([dcl.typedef]),
it is a using-declaration ([namespace.udecl]),
it is a deduction-guide ([temp.deduct.guide]),
it is a static_assert-declaration (Clause [dcl.dcl]),
it is an attribute-declaration (Clause [dcl.dcl]),
it is an empty-declaration (Clause [dcl.dcl]),
it is a using-directive ([namespace.udir]),
it is an explicit instantiation declaration ([temp.explicit]), or
it is an explicit specialization ([temp.expl.spec]) whose declaration is not a definition.
[ Example: all but one of the following are definitions:
int a; // defines a extern const int c = 1; // defines c int f(int x) { return x+a; } // defines f and defines x struct S { int a; int b; }; // defines S, S::a, and S::b struct X { // defines X int x; // defines non-static data member x static int y; // declares static data member y X(): x(0) { } // defines a constructor of X }; int X::y = 1; // defines X::y enum { up, down }; // defines up and down namespace N { int d; } // defines N and N::d namespace N1 = N; // defines N1 X anX; // defines anX
whereas these are just declarations:
extern int a; // declares a extern const int c; // declares c int f(int); // declares f struct S; // declares S typedef int Int; // declares Int extern X anotherX; // declares anotherX using N::d; // declares d
— end example ]
[ Note: In some circumstances, C++ implementations implicitly define the default constructor ([class.ctor]), copy constructor ([class.copy]), move constructor ([class.copy]), copy assignment operator ([class.copy]), move assignment operator ([class.copy]), or destructor ([class.dtor]) member functions. — end note ] [ Example: given
#include <string>
struct C {
std::string s; // std::string is the standard library class (Clause [strings])
};
int main() {
C a;
C b = a;
b = a;
}
the implementation will implicitly define functions to make the definition of C equivalent to
struct C { std::string s; C() : s() { } C(const C& x): s(x.s) { } C(C&& x): s(static_cast<std::string&&>(x.s)) { } // : s(std::move(x.s)) { } C& operator=(const C& x) { s = x.s; return *this; } C& operator=(C&& x) { s = static_cast<std::string&&>(x.s); return *this; } // { s = std::move(x.s); return *this; } ~C() { } };
— end example ]
[ Note: A class name can also be implicitly declared by an elaborated-type-specifier ([dcl.type.elab]). — end note ]
A program is ill-formed if the definition of any object gives the object an incomplete type ([basic.types]).
Appearing inside the braced-enclosed declaration-seq in a linkage-specification does not affect whether a declaration is a definition.