статический полиморфизм c ++ (CRTP), приводящий к неполному типу при оценке «статического constexpr» - PullRequest
1 голос
/ 19 марта 2019

Мне нужен доступ к static constexpr, и одно решение, которое я собрал, работает с gcc ( живой пример ), но не с vc ++ ( живой пример ).

Код выглядит следующим образом:

template<class Drvd>
class Base
{
public:
    static constexpr bool val = Drvd::val;
};

class Derived : public Base<Derived>
{
    friend class Base;
private:
    static constexpr bool val = true;
};

int main()
{
    std::cout << Derived::Base::val << std::endl;
}

Так что это ошибка с vc ++, но у любого есть идея, как достичь val, определенного в Base как значение val в Drvd, иным способом, на который vc ++ не будет жаловаться

Edit: Обратите внимание, что результат аналогичен варианту: friend class Base<Derived>; вместо friend class Base;

Ответы [ 3 ]

1 голос
/ 19 марта 2019

ваша проблема не в объявлениях private / friend (код не скомпилируется, даже если "val" был публичным), ваша проблема в том, что во время создания

static constexpr bool val = Drvd::val

Drvd все еще не завершен. См. Ниже вопрос / ответ о том, как обойти это с классами черт.

Статический полиморфизм C ++ (CRTP) и использование typedef из производных классов

P.S. на самом деле я только что отметил ваш вопрос как дубликат

1 голос
/ 19 марта 2019

Вы можете использовать метод:

#include <iostream>

template<class Drvd>
class Base
{
public:
    static constexpr bool val() { return Drvd::val;  }
};

class Derived : public Base<Derived>
{
    friend class Base<Derived>;
private:
    static constexpr bool val = true;
};

int main()
{
    std::cout << Derived::Base::val() << std::endl;
}

живой пример: https://rextester.com/IHR24393

0 голосов
/ 19 марта 2019

В @David проблема связана с тем, что Face является неполным, потому что оно входит в Base до завершения определения Face.

Однако решение, на которое ссылается @Davidнемного стар и пропускает некоторые уловки, которыми мы можем воспользоваться.А именно, @ms показывает нам, что функции static constexpr хороши - и также основаны на моих собственных экспериментах - и нам действительно нужно иметь дело только с этим конкретным случаем static constexpr переменных и, возможно, типов, к которым обращаются из Derived.

Следующий ( живой пример ) показывает, как решить эту проблему, сохраняя каждый класс в своем собственном h-файле, делая его несколько чище:

#include <iostream>

// Begin: h-file of Base
template<class Drvd>
class ConstValue;

template<class Drvd>
class Base
{
public:
    static constexpr bool val = ConstValue<Drvd>::val;
};
// End: h-file of Base

// Begin: h-file of Derived
class Derived;

template<>
class ConstValue<Derived>
{
public:
    static constexpr bool val = true;
};

class Derived : public Base<Derived>
{
    friend class Base<Derived>;
private:
    static constexpr bool val = true; // optional
};
// End: h-file of Derived

// Main
int main()
{
    std::cout << Derived::Base::val << std::endl;
}

Общая идея заключается в том, что для каждого constexpr, к которому Base необходим доступ из Derived, мы можем создать отдельный класс, который инкапсулирует переменные, и затем перегрузить класс для каждого Derived, который использует Base.

...