Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
488 views
in Technique[技术] by (71.8m points)

c++ - why for-loop isn't a compile time expression and extended constexpr allows for-loop in a constexpr function

I wrote code like this

#include <iostream>
using namespace std;
constexpr int getsum(int to){
    int s = 0;
    for(int i = 0; i < to; i++){
        s += i;
    }
    return s;
}
int main() {
    constexpr int s = getsum(10);
    cout << s << endl;
    return 0;
}

I understand that it works because of extended constexpr. However in this question why-isnt-a-for-loop-a-compile-time-expression, the author gave his code as follow:

#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);
}

It could not compile by GCC5.1, however, after replacing std::get<i>(t); with something without a specified template parameter his code did work. After reading answers under this question I found their main point is constexpr for creates trouble for the compiler so for-loop is used at run-time. So it makes me confused, on one hand, for-loop is at run-time, on the other, the loop is in a constexpr function, so it must be calculated at compile time, so there seems to be a contradiction. I just wonder where did I make a mistake.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This really has nothing to do with whether or not the constexpr function needs to be able to be runnable at compile-time (tuple_size<T>::value is a constant expression regardless of whether the T comes from a constexpr object or not).

std::get<> is a function template, that requires an integral constant expression to be called. In this loop:

for (auto i = 0u; i < std::tuple_size<T>::value; ++i)
{
    std::get<i>(t);
}    

i is not an integral constant expression. It's not even constant. i changes throughout the loop and assumes every value from 0 to tuple_size<T>::value. While it kind of looks like it, this isn't calling a function with different values of i - this is calling different functions every time. There is no support in the language at the moment for this sort of iteration, and this is substantively different from the original example, where we're just summing ints.

That is, in one case, we're looping over i and invoking f(i), and in other, we're looping over i and invoking f<i>(). The second one has more preconditions on it than the first one.


If such language support is ever added, probably in the form of a constexpr for statement, that support would be independent from constexpr functions anyway.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...