3

Consider the code below:

template<char>
struct S { }; 

template<int N>
constexpr auto f(const char (&ref) [N]) {
    return S<ref[0]>{};
}

int main() {
    constexpr auto v = f("foo");
    (void)v;
}

It doesn't compile for ref[0] is not a constant expression.

Anyway, the code below compiles fine:

template<int N>
constexpr auto f(const char (&ref) [N]) {
    return ref[0];
}

int main() {
    constexpr auto v = f("foo");
    (void)v;
}

Should both of them compile or fail to do that for more or less the same reason?

From [expr.const] we have that:

A conditional-expression e is a core constant expression unless the evaluation of e [...] would evaluate one of the following expressions:
[...]
- an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
    - it is initialized with a constant expression or
    - its lifetime began within the evaluation of e;

Anyway, in this case, it is initialized with a constant expression and the lifetime is the same of e, thus the rule doesn't apply.

What's wrong in my reasoning?

As a side question, I would ask if it's possible to use such an array or part of it as a template argument.

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • 2
    Note that a constexpr function can still be called at runtime, and `S` cannot be instantiated at runtime. – kennytm Oct 17 '16 at 14:05
  • @kennytm Note that I'm calling it as `constexpr auto v = f("foo");`. – skypjack Oct 17 '16 at 14:08
  • Doesn't matter, someone else could call it as `char a[10]; randomize(a); f(a)`. – kennytm Oct 17 '16 at 14:09
  • @kennytm I see your point. No chance thus to use it as a template parameter? – skypjack Oct 17 '16 at 14:11
  • I don't think it is possible in general case but if you are using g++ you could make use of its extension in [string literal](https://godbolt.org/g/ffMXRu) – W.F. Oct 17 '16 at 14:23

2 Answers2

2

This:

template<int N>
constexpr auto f(const char (&ref) [N]) {
    return S<ref[0]>{};
}

is ill-formed because according to [temp.arg.nontype]:

A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter.

and from [expr.const]:

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions: [...]
(2.7) — an lvalue-to-rvalue conversion (4.1) unless it is applied to
(2.7.1) — a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or
(2.7.2) — a non-volatile glvalue that refers to a subobject of a string literal (2.13.5), or
(2.7.3) — a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable sub-object of such an object, or
(2.7.4) — a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;

ref[0] requires an lvalue-to-rvalue conversion and none of those sub-bullets apply. Note that ref is not a string literal, so 2.7.2 doesn't apply, nor is it defined with constexpr, because it's a function argument and we don't have that capability.

We basically need the ability to pass string literals as literals, which doesn't exist yet.


The other example:

template<int N>
constexpr auto f(const char (&ref) [N]) {
    return ref[0];
}

doesn't have the converted constant expression required - that one was brought in by the template non-type argument. This code is fine, and would only be problematic if you tried to initialize a constexpr variable with a non-constexpr array value.

Barry
  • 286,269
  • 29
  • 621
  • 977
0

The first example shouldn't compile because you cannot have compiletime-only constexpr functions (or overload on compiletime-ness, like D's __cfte).

Following this reasoning, if you called first example's f at runtime, what would its return type be?

As to the side question: Boost Hana, despite supporting only the newest standard, only uses string literals for runtime stuff, so it may not be possible.

krzaq
  • 16,240
  • 4
  • 46
  • 61