5

In C++ Primer, Fifth Edition, §6.5.2:

A constexpr function is defined like any other function but must meet certain restrictions: The return type and the type of each parameter in must be a literal type (§2.4.4, p. 66), and the function body must contain exactly one return statement

but another sentence in this chapter (page 239):

A constexpr function is permitted to return a value that is not a constant

// scale(arg) is a constant expression if arg is a constant expression
constexpr size_t scale(size_t cnt) { return new_sz() * cnt; }

Is it a contradictory summary? I am confused about it.
The return type of scale is literal type?
update: what's the difference between literal type and constant ?

Community
  • 1
  • 1
Ocxs
  • 149
  • 2
  • 10
  • "Literal Type" doesn't necessarily mean integer constant, like `5`. The standard defines what a literal type is, but I can't be bothered to look it up right now. Here's [cppreference's page on it](http://en.cppreference.com/w/cpp/concept/LiteralType). –  Mar 05 '15 at 14:47
  • 1
    What do you think is contradictory? The types must be literal (such as `size_t`), and the values don't have to be constant. Presumably, §2.4.4, p. 66 describes literal types - it doesn't mean "constant", if that's what you thought. – Mike Seymour Mar 05 '15 at 14:55

3 Answers3

8

First of all what I believe the author meant was that a constexpr function does not have to result in a constant expression, which is an expression that can be evaluated at compile time.

A constexpr function will only yield a constant expression if the arguments to the function are also constant expressions and the comment right after says exactly that:

// scale(arg) is a constant expression if arg is a constant expression

and the examples that follow right after also demonstrate this behavior:

int arr[scale(2)]; // ok: scale(2) is a constant expression
int i = 2; // i is not a constant expression
int a2[scale(i)]; // error: scale(i) is not a constant expression

In C++(as opposed to C99) as array size must be a constant expression and so the last case is an error since the argument to scale is not a constant expression.

This is different concept from the return type of the function, which must be a literal type which is any of the following:

  • void(since c++14) (so that constexpr functions can return void)
  • scalar type which includes Arithmetic types, enumeration types, pointer types, pointer to member types, std::nullptr_- t, and cv-qualified versions of these types)
  • reference type
  • an array of literal type
  • class type that has all of the following properties:
    • has a trivial destructor,
    • is either
      • an aggregate type
      • a type with at least one constexpr (possibly template) constructor that is not a copy or move constructor
    • all non-static data members and base classes are of non-volatile literal types.
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
6

It's not contradictory. As well as mandating that the return type must be of "literal type", the draft standard states that a call to a constexpr function does not have to appear in a constant expression. From the C++11 draft standard:

§7.1.5/7 A call to a constexpr function produces the same result as a call to a equivalent non-constexpr function in all respects except that a call to a constexpr function can appear in a constant expression.

1

constexpr does nothing but tells the compiler that the value is there in compile time, so you can use it as template argument (for example)

int a1 = 5;
std::array<int, a1> arr1; // error, a is variable

const int a2 = 5;
std::array<int, a2> arr2; // OK

int f1() { return 3; }
std::array<int, f1()> arr3; // error, compiler doesn't know it is const 3

constexpr int f2() { return 3; }
std::array<int, f2()> arr4; // OK

Later you also can:

constexpr int f3() { return f1() + 1; } // error, f1 is not constexpr

constexpr int f4() { return f2() + 1; } // OK
std::array<int, f4()> arr5; // OK

Now about literal types limitation: the function arguments and result types should be literal types (Need clarification on definition of literal type), the very same limitation as template arguments apply (known in compile types).

constexpr std::string f5() { return "hello"; } // error, 
                   // std::string is not literal type

constexpr const std::string& f6() { 
  static const std::string s = "hello";
  return s;
}

template<const std::string& s> SomeClass { ... };
SomeClass<f6()> someObject;
Community
  • 1
  • 1
Mux
  • 348
  • 1
  • 6
  • This doesn't answer the question that's asked. It may be somewhat relevant to the question title, but you should really read the full question. –  Mar 05 '15 at 15:12
  • sorry, will be more carefull next time – Mux Mar 05 '15 at 19:28