Если я хочу сделать что-то вроде итерации по кортежу, мне приходится прибегать к сумасшедшим метапрограммированию шаблонов и специализированным помощникам шаблонов. Например, следующая программа не будет работать:
#include <iostream>
#include <tuple>
#include <utility>
constexpr auto multiple_return_values()
{
return std::make_tuple(3, 3.14, "pi");
}
template <typename T>
constexpr void foo(T t)
{
for (auto i = 0u; i < std::tuple_size<T>::value; ++i)
{
std::get<i>(t);
}
}
int main()
{
constexpr auto ret = multiple_return_values();
foo(ret);
}
Потому что i
не может быть const
или мы не сможем его реализовать. Но для циклов есть конструкция времени компиляции, которая может быть оценена статически. Компиляторы могут свободно его удалять, преобразовывать, складывать, разворачивать или делать все, что захотят, благодаря правилу as-if. Но тогда почему нельзя использовать контуры в constexpr? В этом коде ничего не должно быть сделано в "runtime". Это подтверждают оптимизация компилятора.
Я знаю, что вы могли бы изменить i
внутри тела цикла, но компилятор все равно сможет его обнаружить. Пример:
// ...snip...
template <typename T>
constexpr int foo(T t)
{
/* Dead code */
for (auto i = 0u; i < std::tuple_size<T>::value; ++i)
{
}
return 42;
}
int main()
{
constexpr auto ret = multiple_return_values();
/* No error */
std::array<int, foo(ret)> arr;
}
Так как std::get<>()
является конструкцией времени компиляции, в отличие от std::cout.operator<<
, я не могу понять, почему это запрещено.