I have a Config class
// config.hpp
class Config {
public:
static constexpr int a = 1;
static constexpr int b = 1;
}
and include in main.cpp
// main.cpp
#include "config.hpp"
int main () {
std::cout << Config::a << std::endl; // this is ok
std::shared_ptr<otherClass> stream = std::make_shared<otherClass>(
Config::a); // compile error
}
and compiler said that undefined reference to Config::a
and it works when using cout
, but not work when within shared_ptr
constructor.
I have no idea why this happens.
Note that std::make_shared takes parameter by reference, which causes Config::a
to be odr-used because it'll be bound to the reference parameter, then its definition at namespace scope is required (before C++17).
On the other hand, std::cout << Config::a
won't cause Config::a
to be odr-used, because std::basic_ostream::operator<< (int) takes parameter by value, Config::a
is then subject to lvalue-to-rvalue conversion requested to copy-initialize the parameter, therefore Config::a
is not odr-used.
If an object is odr-used, its definition must exist. You can add the definition (in an implementation file) as
constexpr int Config::a; // only necessary before C++17
Note that it cannot have an initializer.
Since C++17 constexpr
static data member is implicitly inline then such definition is not required again, so your code works well from C++17.
If a
static
data member is declaredconstexpr
, it is implicitlyinline
and does not need to be redeclared at namespace scope. This redeclaration without an initializer (formerly required as shown above) is still permitted, but is deprecated.