@NirFriedman Нет никаких исключений - просто все, что вы используете в постоянном выражении, должно использоваться в постоянном выражении. Если вы не используете его, это не должно быть.

раньше я использовал такой код, и ясно, что у компилятора достаточно информации для работы, я не совсем понимаю, почему он компилируется:

template <class T, class I>
auto foo(const T& t, I i) {
    return std::get<i>(t);
}

int main()
{
    std::cerr << foo(std::make_tuple(3,4), std::integral_constant<std::size_t, 0>{});
    return 0;
}

Живой пример:http://coliru.stacked-crooked.com/a/fc9cc6b954912bc5.

Кажется, работает с gcc и clang. Дело в том, что покаintegral_constant имеетconstexpr преобразование в сохраненное целое число,constexpr функции-члены неявно принимают сам объект в качестве аргумента, и поэтому такая функция не может быть использована вconstexpr контекст, если объект, который мы вызываем саму функцию-член, не может рассматриваться какconstexpr.

Вот,i аргумент переданfoo, и поэтомуi безусловно, не может рассматриваться какconstexpr, Тем не менее, это так. Еще более простой пример:

template <class I>
void foo(I i) {
    constexpr std::size_t j = i;
}

Это тоже компилируется, покаstd::integral_constant<std::size_t, 0>{} передаетсяfoo.

Я чувствую, что упускаю что-то очевидное вconstexpr правила. Есть ли исключение для типов без состояний или что-то еще? (или, может быть, ошибка компилятора в двух основных компиляторах? Этот код работает на clang 5 и gcc 7.2).

Изменить: ответ был опубликован, но я не думаю, что это достаточно. В частности, учитывая последнее определениеfoo, Почему:

foo(std::integral_constant<std::size_t, 0>{});

Компилировать, но не:

foo(0);

И 0 иstd::integral_constant<std::size_t, 0>{} являются постоянными выражениями.

Редактировать 2: Кажется, это сводится к тому, что вызовconstexpr Функция-член даже для объекта, который не является константным выражением, сама может рассматриваться как константное выражение, если толькоthis не используется. Это воспринимается как очевидное. Я не считаю это очевидным:

constexpr int foo(int x, int y) { return x; }

constexpr void bar(int y) { constexpr auto x = foo(0, y); }

Это не компилируется, потому чтоy как перешли вfoo не является постоянным выражением. Это не используется, не имеет значения. Таким образом, полный ответ должен показать какой-то язык из стандарта, чтобы оправдать тот факт, чтоconstexpr Функция-член может использоваться как константное выражение, даже для объекта с неконстантным выражением, еслиthis не используется.

Ответы на вопрос(2)

Ваш ответ на вопрос