Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

static constexpr class members are required to have a definition #788

Closed
kivadiu opened this issue Jun 21, 2018 · 6 comments
Closed

static constexpr class members are required to have a definition #788

kivadiu opened this issue Jun 21, 2018 · 6 comments

Comments

@kivadiu
Copy link

kivadiu commented Jun 21, 2018

The following program does not compile with clang++ 5.0.2. With g++ 7.3.0, it does not compile in debug mode but compiles with -O2. The error is that the class static constexpr int i is required to have an address because fmt::format takes its arguments by const reference. However I do not understand why g++ work in release mode! Would it be possible that fmt::format takes its arguments by universal references &&? Would that improve this situation?

#include <iostream>
#include <fmt/format.h>

struct Foo {
  static constexpr auto i = 42;
  void operator()() const { std::cout << fmt::format("{}\n", i); }
};

int main() {
  Foo{}();
  return 0;
}
@vitaut
Copy link
Contributor

vitaut commented Jun 22, 2018

I don't see any error with clang 5.0: https://godbolt.org/g/DrbUZe

@kivadiu
Copy link
Author

kivadiu commented Jun 22, 2018

The problem is not at compile time but at link time, you can see it if you click on 11010 in godbolt:

/tmp/example-852a44.o: In function `Foo::operator()() const':
<source>:6: undefined reference to `Foo::i'

@vitaut
Copy link
Contributor

vitaut commented Jun 24, 2018

Would it be possible that fmt::format takes its arguments by universal references &&? Would that improve this situation?

No, it wouldn't, e.g.

struct Foo {
  static constexpr auto i = 42;
};

template <typename T>
void f(T&& i) {}

int main() {
  f(Foo::i);
}

gives

Undefined symbols for architecture x86_64:
  "Foo::i", referenced from:
      _main in test1-c21676.o

According to [basic.def.odr]:

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required.

This requirement was relaxed in C++17, so your example should compile there. On C++14 and earlier you should provide an out-of-class definition of your variable.

@vitaut vitaut closed this as completed Jun 24, 2018
@kivadiu
Copy link
Author

kivadiu commented Jun 24, 2018

In fact with c++17, it fails both with g++ 8.1.0 and clang 6.0.0 with a much less easy to understand message.
https://godbolt.org/g/dAnHxG

@vitaut
Copy link
Contributor

vitaut commented Jun 24, 2018

That's because Compiler Explorer doesn't link with the fmt library. Your example compiles when using header-only mode: https://godbolt.org/g/DhyUfd

@kivadiu
Copy link
Author

kivadiu commented Jun 25, 2018

OK, thanks, I did not know that godbolt could not link with libraries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants