Возможно ли создавать шаблоны с использованием цикла for в функции constexpr С++ 14?

Я возился с SVN-сборкой clang, чтобы экспериментировать с непринужденными правилами для constexpr. Одной из вещей, которые мне пока не удалось определить, является возможность циклического прохождения элементов внутри кортежа во время компиляции в функции constexpr.

Поскольку у меня нет стандартной библиотеки, совместимой с С++ 14 для тестирования, я подготовил следующий эквивалентный тест:

template<int N>
constexpr int foo() {
  return N;
}

constexpr int getSum() {
  auto sum = 0;
  for (auto i = 0; i < 10; ++i) {
    sum += foo<i>();
  }
  return sum;
}

constexpr auto sum = getSum();

Интересная часть здесь foo<i>(). В функции, отличной от constexpr, я ожидал бы, что это не скомпилируется, потому что вы просто не можете использовать runtime int для создания экземпляра шаблона во время компиляции. Однако, поскольку это функция constexpr, я задаюсь вопросом, возможно ли это. В частности, значение известно во время компиляции, даже если ему разрешено мутировать.

Я знаю, что следующий код будет скомпилирован:

constexpr auto nValue = 2;
foo<nValue>();

В SVN clang мой первый пример не делает:

test2.cpp:19:12: error: no matching function for call to 'foo'
    sum += foo();
           ^~~~~~
test2.cpp:11:15: note: candidate template ignored: invalid explicitly-specified
      argument for template parameter 'N'
constexpr int foo() {
              ^

Во-первых, я пытаюсь интерпретировать вторую часть этого сообщения об ошибке. В стороне, это предусмотрено стандартом С++ 14, и если да, то кто-нибудь знает, почему этот синтаксис не будет разрешен (простой надзор или защита от чего-то)?

Ответ 1

В стороне, это предусмотрено стандартом С++ 14, и если да, то кто-нибудь знает, почему этот синтаксис не будет разрешен (простой контроль или защита от чего-то)?

Это потому, что constexpr не является эксклюзивным для вычислений или использования времени. Функция constexpr - это просто то, что позволяет использовать функцию (или переменную) в постоянном выражении. Кроме того, они являются регулярными функциями. Постоянное выражение просто так требуется в определенных контекстах, таких как static_assert или размеры массива и т.д., Которые являются только ситуациями времени компиляции.

В коде вы заметите, что вы перебираете переменную, но переменная, которую вы зацикливаете сама по себе, не является constexpr, поэтому в этом экземпляре шаблона N не используется константное выражение, Как бы то ни было, это не отличается от этого в С++ 11:

constexpr bool f(int x) {
    static_assert(x > 10, "..."); // invalid
    return true;
}

Что явно недействительно, поскольку, как я упоминал ранее, вам не нужно использовать функции constexpr в исключительных ситуациях компиляции. Например, ничто не мешает вам сделать это:

constexpr int times_ten(int x) {
    return x * 10;
}

int main() {
   int a = times_ten(20); // notice, not constexpr
   static_assert(times_ten(20) == 200, "...");
   static_assert(a == 200, "..."); // doesn't compile
}