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.

ronaldo
  • 455
  • 3
  • 9
  • OK, I admit to being a bit 'weak' in template metaprogramming, but *which* value of `i` should be used *when*? – Adrian Mole Jan 29 '22 at 13:14
  • If `i` is a constant, its value cannot be changed right?? but `for loop` changes the value of `i` on every loop? – pvc Jan 29 '22 at 13:20
  • 1
    BTW: why not decltype( std::get(tuple)); ready to use :-) – Klaus Jan 29 '22 at 13:28
  • 1
  • @user3840170 Is it possible to be accepted by the committee? – 康桓瑋 Jan 29 '22 at 13:37
  • 1
    @康桓瑋 With any luck, it should be included in the next version of the standard. – user3840170 Jan 29 '22 at 13:38
  • @Klaus Just because I was testing ideas while thinking in different ways to teach template metaprogramming to students :) – ronaldo Jan 29 '22 at 19:37
  • 1
    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 :-) – Klaus Jan 29 '22 at 19:53
  • @Klaus 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. – ronaldo Jan 29 '22 at 20:14

2 Answers2

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.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • 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 :) – ronaldo Jan 29 '22 at 19:39
  • 1
    @ronaldo 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. – user17732522 Jan 29 '22 at 19:45
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.

user3840170
  • 26,597
  • 4
  • 30
  • 62