Вызов функции constexpr, принимающей массив, не компилируется

Рассмотрим этот код:

#include <array>

template < int... Ints >
constexpr std::array<int,sizeof...(Ints)> theIntArray = {Ints...};

template < size_t NN >
constexpr void test(const std::array<int,NN>& xx)
{
    theIntArray<xx[0]>;
}

constexpr std::array<int,2> aa = {10,20};

int main()
{
    theIntArray<aa[0]>; // passes
    test(aa); // FAILS ?!

    return 0;
}

в main() Функция проходит первую строку, в то время как вторая строка завершается ошибкой со странным сообщением об ошибке:

error: ‘* & xx’ is not a constant expression
note: in template argument for type ‘int’

Я использую gcc-7.0.1, и вы можете найти живой пример здесь.

Это по стандарту или это баг? Что приводит к сбою второй строки при прохождении первой строки?

2 ответа

Решение

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

theIntArray<xx[0]>;

это только правильный синтаксис, если xx[0] является constexpr, но в теле функции xx не constexpr,

template < size_t NN, std::array<int,NN> const& xx >
constexpr void test()
{
  theIntArray<xx[0]>;
}

живой пример.

Разница в том, что параметр функции constexpr не существует. То есть вы не можете сделать

constexpr auto fun(int x) {
    constexpr y = x;
    return y;
}

и ни вы не можете использовать параметр функции xx[0] в качестве нетипового шаблона-параметра внутри функции. Это отличается для aa[0] потому что это оценивается вне функции.

Единственный способ сделать то, что вы хотите, это сделать параметр функции нетипичным параметром шаблона. Чтобы сделать это, посмотрите ответ @Yakk, где он использует const-ссылку на constexpr массив как нетипичный параметр шаблона.

Другие вопросы по тегам