1

So I've got this code (compiling with clang x86-64 14.0.0):

#include <cstdlib>

template <int size>
struct container {
    char data[size];
};

template <size_t n>
consteval size_t func2(const char (&string)[n]) {
    return 1;
}

template <size_t n>
consteval auto func1(const char (&string)[n]) {
    container<func2(string)> result { };
    return result;
}

int main() {
    static constexpr auto var = func1("hi");
}

The issue comes into play at the func2(string) function call. Replacing string with any string literal yields a successful compilation, whereas leaving string as-is causes a compiler error:

non-type template argument is not a constant expression

I fail to see why this non-type template parameter is not a constant expression, does someone have an explanation?

9
  • 3
    function parameters are never constant expressions. Commented Sep 26, 2022 at 18:18
  • @NathanOliver: While that's true, consteval functions have certain interactions with the parameters of consteval functions. Commented Sep 26, 2022 at 18:25
  • @NathanOliver That seems intensely unreasonable in the context of consteval functions. Are there any plans to remove this restriction? Commented Sep 26, 2022 at 18:29
  • 1
    @NikTedig Not that I am aware of. Here is some good reading about this: stackoverflow.com/questions/56130792/… Commented Sep 26, 2022 at 18:34
  • 1
    @NathanOliver The special behavior is that a call to a consteval function inside another consteval function doesn't require the nested consteval function call to be a constant expression by itself as well. But I don't think there is anything special if the call is part of an expression that is required to be a constant expression. Commented Sep 26, 2022 at 18:59

1 Answer 1

0

That the function is consteval is not relevant. The expression in the template argument must by itself be a constant expression, which it is not because string is a reference-type function parameter (and so its lifetime didn't start with the evaluation of this constant expression) and can't be named to in a constant expression.

If it wasn't required that the expression is by itself a constant expression regardless of whether it is located in a consteval function or called as part of a constant expression, then you would be able to change the type of an expression as a function of the value passed as function argument. That is not compatible with the type system. (What would e.g. the result of decltype/std::declval on a call to such a function be?)

However, your functions don't actually try to retrieve the value or address of the object that string references at all. So it seems like that shouldn't be an issue and it doesn't have to be.

Up to C++20 there is simply a somewhat unnecessary restriction on constant expressions which disallow naming a reference which is not usable in constant expressions, even if no value or address of the referenced object is accessed. With a non-reference parameter on func1 it would work (but then built-in arrays don't support that).

The restriction will be lifted in C++23 through P2280, apparently also as a defect report against previous C++ revisions according to the poll results mentioned in the document. The paper mentions basically the same example of obtaining the size of an array. Again, consteval is not relevant to this though.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.