Leaving member functions undefined
A function is only required to be defined if it is odr-used.
One and only one definition of every non-inline function or variable that is odr-used (see below) is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined.
4) Functions are ODR-used if
- A function whose name appears as a potentially-evaluated expression (including named function, overloaded operator, user-defined conversion, user-defined placement forms of operator new, non-default initialization) is odr-used if it is selected by overload resolution, except when it is an unqualified pure virtual member function or a pointer-to-member to a pure virtual function (since C++17).
- virtual member function is odr-used if it is not a pure virtual member function (addresses of virtual member functions are required to construct the vtable)
- An allocation or deallocation function for a class is odr-used by a new expression appearing in a potentially-evaluated expression
- A deallocation function for a class is odr-used by a delete expression appearing in a potentially-evaluated expression
- A non-placement allocation or deallocation function for a class is odr-used by the definition of a constructor of that class.
- A non-placement deallocation function for a class is odr-used by the definition of the destructor of that class, or by being selected by the lookup at the point of definition of a virtual destructor
- An assignment operator in a class T that is a member or base of another class U is odr-used by an implicitly-defined copy-assignment or move-assignment functions of U.
- A constructor (including default constructors) for a class is odr-used by the initialization that selects it.
- A destructor for a class is odr-used if it is potentially invoked
https://en.cppreference.com/w/cpp/language/definition
To restate your question: Is the following complete program legal?
struct A {
void f() {};
void g(); // Declared but not defined (and not used).
};
int main() {
A a;
a.f();
}
Yes
I am using n4296 which is the C++14 draft, but this has not changed over the years.
9.3 p4 [class.mfct] says:
There shall be at most one definition of a non-inline member function in a program; no diagnostic is required.
Note the "at most" - thus zero definitions are allowed.