Why can't we use compile-time 'variables' in consteval functions as template parameters?
Asked Answered
D

2

8

I was testing this code (https://godbolt.org/z/fe6hhbeqW)...

// Returns the nth type in a parameter pack of types (ommited for clarity)
//   template <std::size_t N, typename...Ts>
//   nth_type{}

template <typename... Ts>
struct Typelist{
    template <typename T>
    consteval static std::size_t pos() noexcept { 
        for(std::size_t i{}; i < sizeof...(Ts); ++i) {
            using TN = nth_type_t<i, Ts...>;
            if (std::is_same_v<T, TN>) 
                return i;
        }
        return sizeof...(Ts);
    }
};

and I was puzzled for it not working. GCC and clang agree on i not being a constant expression, so they refuse to let me pass it as a template parameter. However, i is clearly known at compile-time so, to my limited understanding, the compiler shouldn't have any problem to use it to instantiate the template.

Is there a reason for this not to work? Will it work in the future? I have tested with trunk versions of both compilers, with same result.

Dogtired answered 29/1, 2022 at 13:7 Comment(9)
OK, I admit to being a bit 'weak' in template metaprogramming, but which value of i should be used when?Orlina
If i is a constant, its value cannot be changed right?? but for loop changes the value of i on every loop?Pugging
BTW: why not decltype( std::get<n>(tuple<pack...>)); ready to use :-)Acis
<wg21.link/p1306>Osteopath
@Osteopath Is it possible to be accepted by the committee?Traweek
@康桓瑋 With any luck, it should be included in the next version of the standard.Osteopath
@Acis Just because I was testing ideas while thinking in different ways to teach template metaprogramming to students :)Dogtired
If you ask only for "academic" reasons, you should mention it in your question. This helps others to not write time wasting uninteresting answers. No problem for me as it was only a oneliner, but if someone writes a elaborated solution which solves the underlying problem but is not of your interest... you know :-)Acis
@Acis Yeah, good point to keep in mind :). Not wanting to bother anyone or make you waste your time, of course. I very much value your answers :). Actually I asked the question because I found this situation while designing lessons and it seemed ilogical to me. In fact, even having read the answers, and understood the rationale, I still find it an unnatural contraint of the language.Dogtired
R
11

It doesn't matter that i is guaranteed to be evaluated only at compile-time when its value is known in an abstract sense.

It also doesn't matter whether the function is consteval or constexpr or none of these.

The language is still statically typed and nth_type_t<i, Ts...>; must in any given instantiation of the function refer to exactly one type. If i can change in the for loop, that is not possible to guarantee.

The language requires that the expression i when used as template argument is by itself a constant expression, independently of whether the whole function body can only be evaluated as part of a larger constant expression. But i is neither declared constexpr, nor declared const with constant initializer.

Rand answered 29/1, 2022 at 13:14 Comment(2)
Although I was guessing something like this, it still seemed completely intuitive to me that using a value that is known at compile-time should work the same as a constant expression. After all, the gist of it is that the compiler must know its value during compilation. Thank you very much for the answer :)Dogtired
@Dogtired I think it is easier to understand if one realizes that the language works at compile-time the same way it does at runtime. There are (almost) no special rules about how constexpr and consteval functions are evaluated.Rand
O
7

While this is not possible currently like the other answer says, there is a proposal in the works that would make this kind of loop possible to write. (I am told it was even meant to be included in C++20, but for whatever reason, it was left out at the last moment.)

The proposal is P1306, currently named ‘Expansion Statements’, and with any luck it should be included in C++23. There is a tracking issue on GitHub; the committee proceedings, however, are only visible to members.

Osteopath answered 29/1, 2022 at 14:32 Comment(2)
Nice to know of the proposal. Hope it gets accepted. And thank you very much for the reference :)Dogtired
It seems it missed C++23 per the tracking issue.Talca

© 2022 - 2024 — McMap. All rights reserved.