Какая польза от constexpr для неконстантной функции-члена? - PullRequest
0 голосов
/ 03 мая 2018

Принятый ответ в ошибка компиляции литерального класса с конструктором и функцией constexpr (отличаются vc, g ++) показывает, что в C ++ 14 существует различие в способах constexpr int A::a() и constexpr A::a() const использоваться. то есть constexpr для функции-члена не означает, что функция не изменяет объект, на который она действует.

Данный пример:

struct A {
    constexpr A() {}
    constexpr int a() {return 12; }
    constexpr int b() const {return 12; }
};

int main()
{
    constexpr A a;
    // DOES NOT COMPILE as a() is not const
    // constexpr int j = a.a();
    const int k = a.b(); // Fine since b() is const
}

Мне constexpr на a() кажется бесполезным. Есть ли конкретное применение для constexpr для не-1014 * функций-членов?

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Вопрос: как создать массив constexpr размером 1024 со всеми элементами, установленными на 0, кроме элемента 42, который должен быть 11?

#include <array>

constexpr auto make_my_array() -> std::array<int, 1024>
{
    std::array<int, 1024> a{};
    a[42] = 11; // std::array::operator[] is constexpr non-const method since C++17

    return a;
}

auto test()
{
    constexpr std::array<int, 1024> a = make_my_array();
}

Или еще лучшее предложение от @ michael-anderson a make_iota_array:

template <std::size_t N>
constexpr auto make_iota_array() -> std::array<int, N>
{
    std::array<int, N> a{};

    for (std::size_t i = 0; i < N; ++i)
        a[i] = i;

    return a;
}
0 голосов
/ 03 мая 2018

constexpr означает "может использоваться, когда требуется постоянное выражение" . «подразумеваемое константное» для объявленных объектов не означает, что мы не можем иметь неконстантные объекты в других контекстах. Например, несколько надуманный пример, созданный из вашего собственного:

template<int>
struct foo {
};

struct A {
    int i = 0;
    constexpr A() {}
    constexpr int a() { return i; }
    constexpr int b() const {return 12; }
    constexpr A&  c() { ++i; return *this; }
};

int main()
{
    foo<A{}.c().a()> f1;
}

Очевидно, что аргумент шаблона должен быть константным выражением. Теперь A{} - это значение литерального типа с constexpr c'tor, и это неконстантный объект. Функция-член может изменять эту «константу», потому что во время компиляции все вычисления могут свернуться в константное выражение. Это обоснование правил, с одной стороны.

...