I am confused about a constexpr function? - c++

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 ?

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.

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.

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;

Related

Why can't constexpr be used for non-const variables when the function only uses the types?

Maybe the title is not clear, so concretely:
#include <type_traits>
template<typename T>
constexpr int test(T)
{
return std::is_integral<T>::value;
}
int main()
{
constexpr int a = test(1); // right
constexpr int b = test(1.0); // right
int c = 2;
constexpr int d = test(c); // ERROR!
return 0;
}
In fact, the function doesn't use anything but the type of the parameter, which can be determined obviously in the compilation time. So why is that forbidden and is there any way to make constexpr get the value when only the type of parameter is used?
In fact, I hope to let users call the function through parameters directly rather than code like test<decltype(b)>, which is a feasible but not-convenient-to-use way, to check if the types of parameters obey some rules.
Just take T by reference so it doesn't need to read the value:
template<typename T>
constexpr int test(T&&)
{
return std::is_integral<std::remove_cvref_t<T>>::value;
}
You can even declare test with consteval, if you want to.
(Note that stripping cv-qualifiers isn't necessary in this instance; cv-qualified integral types satisfy the std::is_integral trait.)
Why can't constexpr be used for non-const variables when the function only uses the types?
Because the call expression test(c) is not a constant expression and hence it cannot be used as an initializer for d.
Basically, for the call expression test(c) to be a constant expression, c must be a constant expression. It doesn't matter whether c is used or not inside the function itself. This is why, the call expressions test(1) and test(1.0) works and can be used as an initializer for a and b respectively.

Non-constexpr variable sometimes usable in a constexpr context?

Take a look at the following code example:
template<bool val>
struct test {
static const int value_a = val;
const int value_b = val;
constexpr int get_value_a() const noexcept { return value_a; }
constexpr int get_value_b() const noexcept { return value_b; }
};
int main(int argc, char** argv) {
auto t = test<true>{};
static_assert(t.value_a);
// static_assert(t.value_b);
static_assert(t.get_value_a());
// static_assert(t.get_value_b());
}
Both gcc and clang agree that this should compile, but including any of the commented out static asserts makes it invalid. For example, gcc would then produce these error messages:
error: non-constant condition for static assertion
error: the value of ‘t’ is not usable in a constant expression
note: ‘t’ was not declared ‘constexpr’
This makes perfect sense to me and is exactly what I would have thought. But I don't really know why the other two static asserts compile in the first place. What is the relevant paragraph from the standard that allows this?
In particular, how is this formalized? Is there a clearly defined difference between just using a variable, versus actually accessing its runtime value (which then would be the only forbidden thing in a constexpr context)?
It's just the rules. Before constexpr, const variables initialised with constant expressions could be used as constant expressions themselves (Also for some compatibility with C)
From the standard [expr.const]/3:
A variable is usable in constant expressions after its initializing declaration is encountered if [...] it is a constant-initialized variable [...] of const-qualified integral or enumeration type.
This wouldn't extend to const auto t = test<true>{} because test<true> is not an integral type (You would need to have constexpr auto t = test<true>{}, as expected, following the rules of the rest of that paragraph)
In particular, how is this formalized?
http://eel.is/c++draft/expr.const#4.1
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
this ([expr.prim.this]), except in a constexpr function ([dcl.constexpr]) that is being evaluated as part of e;
Access to non-static members evaluates the this pointer. Access to a static member does not.

A constexpr function is not required to return a constant expression?

C++ Primer (5th edition) on page 240 has a note stating:
"A constexpr function is not required to return a constant expression".
A question has been asked about this: can constexpr function return type be a non const?. The author of that question misunderstood the note.
But what is the correct understanding of it (the answers to the cited post clarify the confusion of that post's author, but do not answer my question)?
A constexpr function must return* must have a path that returns a constant expression iff all parameters are constant expressions. This actually makes sense. Example:
constexpr int square(int i){
return i*i;
}
std::array<int, square(2)> ia; //works as intended, constant expression
int i;
std::cin >> i;
int j = square(i); //works even though i is not a constant expression
std::array<int, square(i)> ia; //fails, because square does not (and cannot)
//return a constant expression
*Correction by chris.
A (non-template) constexpr function must have at least one execution path that returns a constant expression; formally, there must exist argument values such that "an invocation of the function [...] could be an evaluated subexpression of a core constant expression" ([dcl.constexpr]/5). For example (ibid.):
constexpr int f(bool b) { return b ? throw 0 : 0; } // OK
constexpr int f() { return f(true); } // ill-formed, no diagnostic required
Here int f(bool) is allowed to be constexpr because its invocation with argument value false returns a constant expression.
It is possible to have a constexpr function that cannot ever return a constant expression if it is a specialization of a function template that could have at least one specialization that does return a constant expression. Again, with the above:
template<bool B> constexpr int g() { return f(B); } // OK
constexpr int h() { return g<true>(); } // ill-formed, no diagnostic required

Some const char * are unavailable at compile time?

Let's suppose we have a template function with non-type parameter of const char * like this:
template <const char * MESSAGE> void print() {
std::cout << MESSAGE << '\n';
}
Using this template wouldn't be a problem as log as the MESSAGE can be deduced at compile-time, so the following uses are legal:
namespace {
char namespace_message[] = "Anonymous Namespace Message";
constexpr char namespace_constexpr_message[] = "Anonymous Namespace Constexpr Message";
}
char message[] = "Message";
constexpr char constexpr_message[] = "Constexpr Message";
int main()
{
print<namespace_message>();
print<namespace_constexpr_message>();
print<message>();
print<constexpr_message>();
return 0;
}
But the ones below are not (see here):
namespace {
const char namespace_const_message[] = "Anonymous Namespace Const Message";
}
const char const_message[] = "Const Message";
int main()
{
print<namespace_const_message>();
print<const_message>();
print<"Literal">();
return 0;
}
The errors generated by the code above are the following:
the value of '{anonymous}::namespace_const_message' is not usable in a constant expression
I don't get why namespace_const_message is not usable in a constant expression while namespace_message is; if I must bet for one of them to be unable to be used in a constant expression I'll bet for the no constant one, but is the one which already works as constant expression!
note: '{anonymous}::namespace_const_message' was not declared 'constexpr'
namespace_message was neither declared as constexpr and is used into a constant expression and its value is deduced at compile time. Why constexpr is needed if the expression is const and not required if no-const?
Same goes for the values outside the anonymous namespace, I was trying to force the compile-time-constness placing the values into a internal linkage space but is obvious that I've failed.
Finally, the last error:
'"Literal"' is not a valid template argument for type 'const char*' because string literals can never be used in this context
So, surprisingly (at least it was a surprise for me) a string literal cannot be used as template argument, but as long as the string (well, a pointer to a null-terminated array of characters) is a compile-time value it can be used as non-type template parameters so: they're available at compile-time as long as "they are a lvalue" (but they're already lvalues!).
I'm trying to guess why a string literal can never be used in this context, and my best guess is that two string literals with the same content aren't the same literal (because the pointer which points to the content could be different) while two integral literals are the same (they're a value, not a pointer to a value).
So, what's the question here?
Why the namespace_const_message and const_message aren't available at compile-time and thus forbidden in the print template function?
Is my guess about the string literals correct?
Thanks.
The instantiation variable of a template needed to have external
linkage, and const was implicitly internal linkage. So you have to
write:
extern char const constMessage[] = "Const message";
(Another alternative would be for it to be a static class member.
Static class members always have external linkage.)
The case of string literals is in some ways similar: their type is
char const[]. But it's even worse: template instantiations (at least
the early ones) need a name, and a string literal doesn't have one.
Even more to the point, it's unspecified whether identical string literals
are the same object or not, so in the following:
template <char const* m>
struct Toto { char const* f() const; };
Toto <"titi"> t1;
Toto <"titi"> t2;
it would be unspecified whether t1 and t2 had the same type or not.
From the c++11 standard §14.3.2.1
Template non-type arguments
A template-argument for a non-type, non-template template-parameter shall be one of:
for a non-type template-parameter of integral or enumeration type,
a converted constant expression (5.19) of the type of the
template-parameter; or
the name of a non-type template-parameter; or
a constant expression (5.19) that designates the address of an
object with static storage duration and external or internal linkage
or a function with external or internal linkage, including function
templates and function template-ids but excluding non-static class
members, expressed (ignoring parentheses) as & id-expression, except
that the & may be omitted if the name refers to a function or array
and shall be omitted if the corresponding template-parameter is a
reference; or
a constant expression that evaluates to a null pointer value (4.10); or
a constant expression that evaluates to a null member pointer value (4.11); or
a pointer to member expressed as described in 5.3.1; or
an address constant expression of type std::nullptr_t.
To your questions:
Why the namespace_const_message and const_message aren't available at compile-time and thus forbidden in the print template function?
That's why constexpr exists. They can be used where it's needed compile-time evaluation, thus available to be template-arguments.
Is my guess about the string literals correct?
There is a note about this right after the arguments:
Note: A string literal (2.14.5) does not satisfy the requirements of any of these categories and thus is not
an acceptable template-argument.
You can also use a std::array<char, N>. The sample below requires C++20:
#include <array> // std::array
#include <cstddef> // std::size_t
template <auto constexpr_string>
void needs_constexpr_string() {
// ... use the string ...
}
template <auto N>
consteval auto str(char const (&cstr)[N]) {
std::array<char, N> arr;
for (std::size_t i = 0; i < N; ++i)
arr[i] = cstr[i];
return arr;
}
int main() {
needs_constexpr_string<str("Hello World")>();
}

why is a const array not accessible from a constexpr function?

i have a constexpr function named access, and i want to access one element from an array:
char const*const foo="foo";
char const*const bar[10]={"bar"};
constexpr int access(char const* c) { return (foo == c); } // this is working
constexpr int access(char const* c) { return (bar[0] == c); } // this isn't
int access(char const* c) { return (bar[0] == c); } // this is also working
i get the error:
error: the value of 'al' is not usable in a constant expression
why can't i access one of the elements from access? or better how do i do it, if it is even possible?
The array needs to be declared constexpr, not just const.
constexpr char const* bar[10]={"bar"};
Without that, the expression bar[0] performs an lvalue-to-rvalue conversion in order to dereference the array. This disqualifies it from being a constant expression, unless the array is constexpr, according to C++11 5.19/2, ninth bullet:
an lvalue-to-rvalue conversion unless it is applied to
a glvalue of literal type that refers to a non-volatile object defined with constexpr
(and a couple of other exceptions which don't apply here).