Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

undefined reference to const int within shared_ptr

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.

like image 338
alec.tu Avatar asked Oct 13 '17 03:10

alec.tu


2 Answers

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.

LIVE

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 declared constexpr, it is implicitly inline 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.

LIVE

like image 168
songyuanyao Avatar answered Oct 24 '22 01:10

songyuanyao


Your a is private, and either a public: needs to preceed it or make the class a struct to get default public. But this compiles under C++14 https://godbolt.org/g/tS4M1Z

#include <iostream>
#include <memory>

struct Config {
  static constexpr int a = 1;
  static constexpr int b = 1;
};

struct otherClass {
    otherClass( int c ) { }
};

int main () {
  std::cout << Config::a << std::endl; // this is ok
  std::shared_ptr<otherClass> stream = std::make_shared<otherClass>( Config::a ); // compile error
}
like image 1
Beached Avatar answered Oct 23 '22 23:10

Beached