Ковариантные возвращаемые типы виртуального constexpr

Насколько я понимаю из этого предложения C++20 снимает ограничения на использование виртуальных функций в контекстах constexpr. Само изменение простое, слова "не должно быть виртуальным" убраны. Обоснование этого, по-видимому, заключается в том, что динамический тип всего должен быть известен в любом случае, поэтому стоимость его разрешения почти ничтожна.

Меня заинтересовало обсуждение ковариации. В конце статьи приведен пример:

struct X1
{
    constexpr virtual X1 const* f() const { return this; }
};

struct Y
{
    int m = 0;
};

struct X2: public Y, public X1
{
    constexpr virtual X2 const* f() const { return this; }
};

constexpr X1 x1;
static_assert( x1.f() == &x1 );

constexpr X2 x2;
constexpr X1 const& r2 = x2;
static_assert( r2.f() == &r2 );

Судя по моему чтению, вполне вероятно, что decltype(r2.f()) означает X2 const*, а не X1 const*. В конце концов, если динамический тип полностью известен, разве это не самая простая реализация?

Итак, в приведенном выше примере я должен ожидать, что это скомпилируется:

constexpr decltype(r2.f()) zz = &x1;

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


person Flexo    schedule 13.08.2019    source источник
comment
Статический тип выражения не меняется.   -  person T.C.    schedule 13.08.2019


Ответы (1)


В конце концов, если динамический тип полностью известен, разве это не самая простая реализация?

Тот факт, что код вызывается во время компиляции, не означает, что обычные правила C++ приостанавливаются. Если тип выражения является чем-то одним в коде, не выполняющемся во время компиляции, то он будет таким же, если этот код запускается во время компиляции.

Во время выполнения среда выполнения (независимо от того, выполняется ли она во время компиляции или нет) знает динамический тип всех указателей/ссылок на объекты. В конце концов, если бы это было не так, dynamic_cast не смог бы работать. Но это не меняет того факта, что вызов функции базового класса вернет значение, если функция базового класса говорит, что она возвращает значение, независимо от переданного вами динамического типа.

FWIW версии компиляторов, доступные в Интернете, похоже, принимают это, чего я не ожидал.

Оно допустимо, потому что &x1 имеет тип X1*, а выражение decltype имеет тип X1*. Итак, вы просто копируете файл X1*.

person Nicol Bolas    schedule 13.08.2019