сговор в производном классе, лязг против отдыха - PullRequest
0 голосов
/ 27 апреля 2018

Минимальный пример:

#include <cstddef>
struct B
{
    constexpr static const size_t MAX = 10;
};

struct D : B 
{
    constexpr static const size_t MAX = 20;
};

void use(const B& v)
{
    static_assert(v.MAX == 10, "");
}

template<typename X>
void use2(X&& v)
{
    static_assert(v.template MAX == 20, "");
}

int main ()
{
    D d;
    static_assert(d.MAX == 20, "");
    use(d);
    use2(d);

    return 0;
}

GCC (v5.4 ... v7.3): прекрасно компилируется (любой уровень оптимизации и -Wall -Wextra -pedantic) ICC / MSVC: прекрасно компилируется (пробовал с разными версиями на godbolt.org)

CLANG (v4 ... v6): ошибка: выражение static_assert не является целочисленным константным выражением static_assert (v.MAX == 10, "");

РЕДАКТИРОВАТЬ (перефразируя вопрос):

По моему мнению, поведение clang наименее удивительно (или более интуитивно). Учитывая, что это единственный компилятор, который не может скомпилировать приведенный выше код, я хотел бы понять, какое из 2 поведений корректно и почему?

РЕДАКТИРОВАТЬ 2:

Судя по этому добавлению шаблонной функции, gcc ищет использование объявленного типа параметра и определяет, какой член constexpr использовать независимо от того, что было передано.

При передаче по значению clang также оценивает MAX как постоянное выражение. В этом случае очевидно, что v.MAX == 10 будет верным для всех компиляторов для не шаблонной функции.

РЕДАКТИРОВАТЬ 3 (еще более короткая версия): Который до сих пор не компилируется на Clang

#include <cstddef>

struct B
{
     constexpr static const size_t MAX = 10;
};

void use(const B& v)
{
    static_assert(v.MAX == 10, "");
}

template<typename X>
void use2(X&& v)
{
    static_assert(v.template MAX == 10, "");
}

int main ()
{
    B v;
    static_assert(v.MAX == 10, "");
    use(v);
    use2(v);

    return 0;
}

1 Ответ

0 голосов
/ 28 апреля 2018

Clang правильный.

v.MAX == 10 оценивает v, что является ссылкой без предшествующей инициализации. Это не допускается в постоянном выражении.

Обратите внимание, что даже если MAX является статическим элементом, v все еще оценивается во время оценки v.MAX.

Вы можете использовать тип класса для доступа к MAX, чтобы избежать оценки v, например

void use(const B& v)
{
    static_assert(B::MAX == 10, "");
               // ^^^
}

template<typename X>
void use2(X&& v)
{
    static_assert(std::remove_reference_t<X>::MAX == 10, "");
               // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...