6

In this comment to another question, the user hvd stated the following:

... although string literals can be passed to constexpr functions, and array indexing is allowed on string literals in constant expressions, an indexing operation on a constexpr function parameter doesn't qualify as a constant expression.

I didn't fully understand what was meant. Does it mean that the hash_value variable in the following code

#include <cstddef>

// Compute the hash of a string literal adding the values of its characters
template<std::size_t N> constexpr std::size_t
hash_string
    ( const char (& s)[N] )
noexcept
{
    std::size_t h = 0;

    // Array indexing happening under the hood
    for ( const auto c : s )
        h += c;

    return h;
}

constexpr auto hash_value = hash_string("Hello, world!");

cannot be evaluated at compile time? Could you elaborate on the quoted comment and tell if I am right?

Community
  • 1
  • 1
djsp
  • 2,174
  • 2
  • 19
  • 40
  • I don't see anything in C++14 standard that bans this. Your code compiles just fine in clang. – T.C. Sep 18 '14 at 16:12
  • Do many compilers make this kind of optimization? That seems very aggressive. – tadman Sep 18 '14 at 16:13
  • @T.C. Yes, it compiles and works fine for me too on Clang. However, and especially since I don't know assembly, I want to ensure that it is evaluated at compile time. – djsp Sep 18 '14 at 16:13
  • @Kalrish If you write `constexpr auto foo = ...;`, it must be evaluated at compile time. – T.C. Sep 18 '14 at 16:14
  • 3
    Some what related question from yesterday [Computing length of a C string at compile time. Is this really a constexpr?](http://stackoverflow.com/q/25890784/1708801) ... assigning to a `constexp` variable means is will be evaluated at compile time and I don't see any issues with your code either. – Shafik Yaghmour Sep 18 '14 at 16:17
  • @T.C. I thought a `constexpr` declared variable could still exist at run time, at the discretion of the implementation. I will have to revise my `constexpr` knowledge. Thanks for pointing it out. – djsp Sep 18 '14 at 16:17
  • @Kalrish well Bjarne and Herb both say it should be done at compile time but I can not find the text in the draft standard that requires it and Steve Jessop argues it is a quality of implementation issue and believes they really mean any "self-respecting compilers" should do this. – Shafik Yaghmour Sep 18 '14 at 16:18
  • @ShafikYaghmour Well, it must at least qualify for compile-time evaluation as a constant expression. – T.C. Sep 18 '14 at 16:22
  • @ShafikYaghmour Well, [your answer to that question](http://stackoverflow.com/a/25891133/2207421) states it very clear. Taking one of your quotes from Bjarne Stroustrup: "In addition to be able to evaluate expressions at compile time, we want to be able to require expressions to be evaluated at compile time; constexpr in front of a variable definition does that (and implies const)". – djsp Sep 18 '14 at 16:22
  • Looking at the assembly output, clang does evaluate this at compile-time. When you turn on optimizations it will evaluate at compile-time even without `constexpr`. – interjay Sep 18 '14 at 16:23
  • @ShafikYaghmour A nonlocal variable initialized with a constant expression qualifies for *constant initialization*, which, as a type of *static initialization*, must be performed before any dynamic initialization takes place. So I suppose compilers could hypothetically defer evaluation until runtime, but they are rather constrained in what they can do even if they defer it. – T.C. Sep 18 '14 at 16:27
  • @hvd: Can you clarify your comment for OP. – Jarod42 Sep 18 '14 at 17:31
  • @T.C. I agree in that case the compiler has more limited options, I was referring to the more general case. When I originally read the code since there was no `main` it was unclear if I should assume `hash_value` was global or it could be either. – Shafik Yaghmour Sep 19 '14 at 11:59
  • It is at least `as-if` it was evaluated at compile time, with the note that the compiler is free to pause nearly forever at program startup to write sonnets using the infinite monkey technique: few self respecting compilers will do that either. – Yakk - Adam Nevraumont Sep 20 '14 at 11:54

2 Answers2

3

What I was saying in that comment was that you cannot have something like

template <int N>
int f();

constexpr int g(int i) {
  return f<i>(); // invalid
}

because although the result of a constexpr function can be a constant expression, inside the body, its parameters aren't. A constexpr function may be called with constant or with non-constant arguments, the caller gets to decide, and C++ doesn't have any sort of function that can only be called with constant arguments.

It mattered in the answer you were reading because it would have been useful to have a const char (&str)[N] function argument, and treat str[i] as a constant expression inside the function body.

This doesn't matter for the code you've got. That code is fine.

  • Thank you! Now I understand it: a `constexpr` function is _enabled_ to be evaluated at compile time, but not _required_. Thus, it may be used in a context in which constant expressions are required, but it cannot be assumed that it will always run at compile time. That's why `constexpr` function arguments cannot be evaluated in a `static_assert`. – djsp Sep 18 '14 at 20:39
  • +1 (from yesterday) thank you for following up and clarifying. – Shafik Yaghmour Sep 19 '14 at 12:04
2

I went through the relevant sections of both N3337 and N3936, and nothing in either version of the standard prohibits a constexpr function of the sort

template<std::size_t N> constexpr std::size_t
hash_string
    ( const char (& s)[N] )
noexcept
{
    return s[0];
}

And in fact this compiles in both g++ and clang in C++11 mode. I have absolutely no idea where the claim that "an indexing operation on a constexpr function parameter doesn't qualify as a constant expression" came from. I can find nothing in §5.19 [expr.const] that prohibits this.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Can the problem be from use of the `for` loop? – R Sahu Sep 18 '14 at 16:25
  • @RSahu That's a C++14 vs. C++11 issue. The loop isn't allowed in C++11 `constexpr`, but the indexing claim is unrelated to that. – T.C. Sep 18 '14 at 16:25
  • @hvd I would still like to know the reasons for the quoted statement, even after your standard-based explanation. It intrigues me :). – djsp Sep 18 '14 at 17:15