static constexpr na typ własnej klasy

0

Jak (o ile to możliwe) zrobić statyczne pole constexpr typu własnej klasy? Czyli co zrobić by zadziałało takie coś:

#include <complex>

class Foo {
public:
    static constexpr Foo F_ZERO{0};                         // tego nie mozna
    static constexpr std::complex<double> C_ZERO{0.0, 0.0}; // to mozna

public:
    constexpr Foo(int i) : _i(i) {}

private:
    int _i;
};

class Bar {
public:
    static constexpr Foo F_ZERO{0};    // ale gdy Foo jest w innej klasie, to juz mozna
};

Błąd powoduje linia 5 static constexpr Foo F_ZERO{0};.
Linię 6. dałem by sprawdzić czy w ogóle można oznaczać constexpr typy złożone jak klasy. No i się okazuje, że można.
Co więcej dodałem też klasę Bar i okazuje się, że można oznaczyć pole Bar::F_ZERO jako static constexpr.

Więc jak to jest z tym static constexpr? Można mieć pole statyczne i constexpr danego typu ale tylko w innych klasach niż własna? Hmm

Na stackoverflow znalazłem takie rozwiązanie:

struct Cursor {
    static Cursor const ZERO;
    std::size_t row, column;
};

constexpr Cursor const Cursor::ZERO{ 0, 0 };

Z tym, że komentarze do posta wskazują, że to jest rozwiązanie ale tylko w szczególnym przypadku. Nie zawsze to zadziała i nie w każdym standardzie C++.

Na koniec wklejam błąd, jaki się pojawia przy próbie kompilacji:

test.cpp:5:26: error: ‘constexpr const Foo Foo::F_ZERO’ has incomplete type
    5 |     static constexpr Foo F_ZERO{0};
      |                          ^~~~~~

Użyty kompilator: g++ 10.2.0

0

Nie da się tego zrobić w samym headerze.
Można to obejść:

//foo.hh
#ifndef FOO_HH
#define FOO_HH
class Foo
{
public:
  constexpr Foo(int bar): m_bar(bar) {};
  static const Foo foo;
private:
  int m_bar;
};
#endif //FOO_HH

//foo.cc
#include "foo.hh"

//static
constexpr Foo Foo::foo {0};

EDIT: ogólnie to problem w tym, że żeby zadeklarować obiekt jako constexpr nie może to być incomplete-type. Ergo, deklaracja musi wystąpić poza klasą.
Możesz też zrobić tak:

//foo.hh
#ifndef FOO_HH
#define FOO_HH
class Foo
{
public:
  struct Constants;
  constexpr Foo(int bar): m_bar(bar) {};
  static const Foo foo;
private:
  int m_bar;
};

struct Foo::Constants {
  static constexpr Foo foo {0};
};
#endif //FOO_HH

1 użytkowników online, w tym zalogowanych: 0, gości: 1