Разве класс не может иметь статические экземпляры членов constexpr?

Этот код выдает ошибку incomplete type. В чем проблема? Разрешено ли классу иметь статические экземпляры-члены самого себя? Есть ли способ добиться того же результата?

struct Size
{
    const unsigned int width;
    const unsigned int height;

    static constexpr Size big = { 480, 240 };

    static constexpr Size small = { 210, 170 };

private:

    Size( ) = default;
};

person nyarlathotep108    schedule 03.03.2016    source источник
comment
Вы спрашиваете конкретно о constexpr статических членах?   -  person Piotr Skotnicki    schedule 03.03.2016
comment
@PiotrSkotnicki Да. Удаление ключевого слова все равно не заставит его работать.   -  person nyarlathotep108    schedule 03.03.2016
comment
Как только вы удалите ключевое слово, вы можете инициализировать его вне класса, я думаю, когда это уже полный тип   -  person Piotr Skotnicki    schedule 03.03.2016


Ответы (3)


Есть ли способ добиться того же результата?

Под «тот же результат» вы конкретно подразумеваете constexpr-ность Size::big и Size::small? В этом случае, возможно, это будет достаточно близко:

struct Size
{
    const unsigned int width = 0;
    const unsigned int height = 0;

    static constexpr Size big() {
        return Size { 480, 240 };
    }

    static constexpr Size small() {
        return Size { 210, 170 };
    }

private:

    constexpr Size() = default;
    constexpr Size(int w, int h )
    : width(w),height(h){}
};

static_assert(Size::big().width == 480,"");
static_assert(Size::small().height == 170,"");
person Mike Kinghan    schedule 03.03.2016

Классу можно иметь статический член того же типа. Однако класс является неполным до конца его определения, и объект не может быть определен с неполным типом. Вы можете объявить объект с неполным типом и определить его позже, когда он будет завершен (вне класса).

struct Size
{
    const unsigned int width;
    const unsigned int height;

    static const Size big;
    static const Size small;

private:

    Size( ) = default;
};

const Size Size::big = { 480, 240 };
const Size Size::small = { 210, 170 };

см. это здесь: http://coliru.stacked-crooked.com/a/f43395e5d08a3952

Однако это не работает для участников constexpr.

person Brian Bi    schedule 03.03.2016
comment
Как вы думаете, это не работает для constexpr членов, потому что это запрещено стандартом или из-за ошибки компилятора? - person nyarlathotep108; 04.03.2016
comment
@nyarlathotep108 nyarlathotep108 Это не работает, потому что член static constexpr должен быть инициализирован встроенным. - person Brian Bi; 04.03.2016
comment
Как насчет этого подхода? - person xskxzr; 25.06.2018

В качестве обходного пути вы можете использовать отдельный базовый класс, определение которого завершается при определении констант в производном классе.

struct size_impl
{
//data members and functions here
    unsigned int width;
    unsigned int height;
};


struct size:  public size_impl
{
//create the constants as instantiations of size_impl
    static constexpr size_impl big{480,240};
    static constexpr size_impl small{210,170};

//provide implicit conversion constructor and assignment operator
    constexpr size(const size_impl& s):size_impl(s){}
    using size_impl::operator=;

//put all other constructors here
};

//test:
constexpr size a = size::big;

Вы можете поместить базовый класс в отдельное пространство имен, чтобы скрыть его определение, если хотите.

Код компилируется с помощью clang и gcc.

person benb    schedule 26.06.2019