I have a compile-time string class that helps programs compute various relevant things at compile time, such as hash results and a quick lookup table for find, which is constructed like this:
"hello"_constexpr_str;
Also, my string class supports construction from this type, which allows for fast hash and fast find and avoids unnecessary data copying, like this.
defs::string string = "hello"_constexpr_str;
Of course, my string class also supports building from const char_T*
Now here's the problem!
I want to use the constexpr method automatically when my string class is constructed with compile-time constants like string("hell word!") rather than ugly but strong string("hell word!"_constexpr_str)
In other words, I want string("hell word!") to automatically become string("hell word!"_constexpr_str) in compile-time to calculate the information about the constant string and put it in constant state storage, so that all my string class has to do is hold a pointer to constexpr_str_t
//Draft Code
#if defined(__cpp_if_consteval)
#define if_in_consteval if consteval
#else
#define if_in_consteval if constexpr(0)
#endif
constexpr string_t(const constexpr_str_t&str)noexcept;//save a pointer to constexpr_str_t
string_t(const char_T* str)noexcept{
if_in_consteval{
constexpr constexpr_str_t constexpr_str(str);
construct[this](constexpr_str);
}
else{
construct[this](string_view_t(str));
}
}
What do I do to achieve this?
If I understood your question now after the discussion in the comments correctly, you have a operator""_constexpr_str which is marked consteval and returns a string-view-like type constexpr_str_t with some additional information attached based on the contents of the string.
You then have a function taking an (ordinary) string literal as argument with overloads taking either constexpr_str_t or const char*. You basically want the const char* overload to only be chosen when the argument is not a constant expression. Otherwise the constexpr_str_t overload should be chosen and constructed at compile-time (i.e. via consteval) so that the extra information can be attached at compile-time.
This cannot work however, because it is impossible to overload on consteval. Whether or not a consteval function is called depends only on the type of the argument. It is not possible to distinguish between constant expression arguments and non-constant expression arguments.
Trying to determine whether a function argument is a constant expression inside a function is also impossible. Functions are compiled individually. They are not compiled twice depending on whether or not the argument is a constant expression.
The only thing possible is to change behavior based on whether the whole expression that the function call is used in is a context requiring a constant expression. That is what if consteval is for. But if you are making a decision based on such a scenario, you don't need
constexpr constexpr_str_t constexpr_str(str);
You can simply do the calculation for the additional properties of the string there as if at runtime and mark the function constexpr. If used in a context requiring a constant expression it will be evaluated at compile-time.
If you want to enforce this even if the call doesn't happen in a context requiring a constant expression, then it is impossible.
You can however write a macro which tests whether an expression is a constant expression and then conditionally calls either a consteval function or a non-consteval function. It is just impossible through a function call.
You can use the C++20 std::is_constant_evaluated() function found in the <type_traits> header. It detects whether a function call occurs within a constant-evaluated context.
Related
I'm looking for some construct that can detect whether a local expression is a constant expression, or whether it's not, that can be used in a static_assert declaration.
In code:
int main()
{
constexpr int i = 1;
if constexpr(i) {}
static_assert(is_constexpr(i));
int j = 1;
//if constexpr(j) {} // error: 'j' is not usable in a constant expression
static_assert(!is_constexpr(j));
}
The is_constexpr here can be a macro, a class (then probably with other syntax), or a function. How to make is_constexpr(i) return true/true_type and, conversely, is_constexpr(j) return false/false_type?
I tried a lot of the solutions available here on SO (also using old-school SFINAE) without success. I can edit in the links and my failed attempts if required.
Playground on godbolt here
The problem is that parameters (like t) are not constant expressions. For example, we cannot use t as a template non-type parameter, or as a size of a built-in array.
This means that some expression say some_expr( t ) that contains(involves) the subexpression t is itself not a constant expression, either.
Can is_constexpr be a function?
The simple fact that you write is_constexpr(i) means that you're looking for a function of type bool(auto); but you also want to be able to pass it constexpr arguments or non-constexpr arguments, so for sure it can't be consteval otherwise it would error when called in the latter scenario; so you can at most make it constexpr. However, there's no such a thing (yet?) as a constexpr function parameter, so as soon as you pass something to that constexpr function you have no way to detect whether or not the argument was a constant expression at the call site.
Can is_constexpr be a meta-function?
The other opportunity would be to use a metafunction, but how would you expect to call it? If you expect is_constexpr<i>, i.e. passing the entity you are querying as a template argument, that would be clearly only possible if i is constexpr; if you go for is_constexpr<decltype(x)>, you are expecting that decltype(x) contains some info about the constexpr-ness of x, but that's not the case, as constexpr/consteval are not part of the type of an expression.
Do you really need it?
This, I believe, means that whenever you ask whether an expression is a constant expression, you can always find the answer by looking at the code before that expression, and that answer will not depend on any boolean condition, not even a constexpr condition.
In other words, I believe (and happy to be proved wrong), there's no way for an expression appearing in a C++ program to be constexpr or not in the same line of code depending on the path that leads there.
Do we really have a usecase?
I agree that this is likely an XY problem.
So I challenge you to write an example where a given C++ expression of your choice appearing at a certain line of code is constexpr across one branch of execution and non-constexpr across another branch. And the branches can also be compile-time (well, given your question, you were not asking about non-compile-time branching, so in the previous sentence you can can also be are).
cppreference said the following about the body of a constexpr function:
the function body must not contain:
a definition of a variable of non-literal type
a definition of a variable of static or thread storage duration.
All I understood about a constexpr function is that the statements in its body should be evaluated at compile-time so that the call expression can be evaluated at compile-time. Am I true?
Since C++14, the standard allows the body to contain variable definitions of literal types. So what about those definitions, are they evaluated at compile-time or runtime? since non-constexpr variables are allowed also.
What I think I misunderstood is that the compiler shall be able to evaluate at compile-time every statement in a constexpr function body. Does this true since C++14?
To make my confusion clear, I have this simple example:
// assuming std::is_literal_type<T> is true.
constexpr T f() { T t{}; return t; };
I can't understand how the compile behaves with the above snippet. Variable t is an automatic non-const variable and gets defined at run-time not compile-time; so it basically cannot appear in a constexpr declaration. Does this means, the compiler will never evaluate f() at compile-time because it has a statement, that's T t;, which will be evaluated at runtime only.
My confusion is increased when I have tried:
constexpr T result = f();
and it compiles successfully!. Does this mean f() are evaluated at compile-time? if yes, what about the runtime definition of t?
My second question is about why static-duration variables are not allowed in the body of a constexpr function.
the statements in its body should be evaluated at compile-time
...along at least one possible code path.
Or, as the cpprefenrce page you're quoting puts it,
there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression
The function can be doing disk I/O if it wants to, as long as there is an if branch that skips it.
Variable t is ... defined at run-time not compile-time
It's defined in both. There is a run-time definition of the function (actual machine code compiled and written to the object file) and also there is a compile-time version of the function, a bunch of AST nodes or some sort of internal compiler representation of them. In a constexpr context, compile-time version will be evaluated and replaced by its result. In runtime context, a function call instruction will be compiled.
I'm trying to write a class that is closely related to integers, and because of that I included a conversion constructor with the form
constexpr example::example(const int &n);
My question is: if I subsequently define the function
void foo(example n);
and I use it like this
foo(3);
in my code, is the integer literal 3 converted in an instance of example at compile time?
If no, is there a way to obtain this behavior?
If yes, does that still happen if the constructor isn't explicitly declared as constexpr?
The fact that the constructor is constexpr does not force the computation to happen at compile time. It only means that the constructor is eligible to be used within both constant expressions and non-constant expressions.
If on the other hand you declare the constructor consteval, then it means that only constant expressions are allowed to call that constructor. This in turn implies that every invocation of the constructor must be checked by the compiler to ensure that it is a constant expression (because, if it is not, the compiler must diagnose the violation). Since checking that something is a constant expression requires checking whether it contains any undefined behaviour, such checking is as difficult as actually evaluating the expression. Therefore, you can be assured that declaring a constructor (or any other function) consteval will ensure that the function will not be called at runtime: the compiler is allowed to generate code to re-evaluate it at runtime, but there is no reason why it would do so. The downsides of this approach are that, first, it becomes impossible to use the constructor in a non-constant expression, and second, constant expression evaluation is much slower than runtime evaluation, and you have to decide whether the increased compile times are worth it.
If you leave the constructor as constexpr then you can still force it to be called at compile time in particular instances by using a constexpr variable:
constexpr example ex = 3; // evaluated at compile time
foo(ex);
This is a consequence of the fact that a constexpr variable is only allowed to be initialized by a constant expression.
In addition to the answer by Brian Bi, it should be mentioned that compiler optimization may cause the evaluation to happen at compile time in your example.
Look at this compilation without optimization https://godbolt.org/z/EccGosc7n versus the same code compiled with -O3: https://godbolt.org/z/Kz51x4acK.
I need an explanation for this. How does lambda differ from others function to it don't be allowed? Is this a nonsense to be not part of C++ standard? for example, I wanted to write a "nested" function in C++ but like it isn't possible to do directly I do use lambda instead of. This function does a very small job: take a single int parameter and multiply with some values and returns. This values are locals to where lambda function is defined and all them are constexpr and know at run-time for this reason I do want to let the compiler put a const value instead of call the function. It's very often used function (that's why I write this as function) and I don't want this beging computed at run-time.
It is because the standard list lambda as non constant expression : "5.19 Constant expressions" … "is a core constant expression unless it involves one of the following as a potentially evaluated subexpression" … "— a lambda-expression (5.1.2);"
That is enough for any compiler to reject constexpr function with a lambda involved.
With the new C++11 standard, when should I use the inline keyword over the constexpr keyword? Does the constexpr keyword offer any additional optimization over inline, or does it merely assert that things must be computed at compile-time?
Why does constexpr work on the GCC in some cases where the call is not constant, such as calling foo(x) on a non-constexpr variable? Is this a bug in the GCC or is it actually part of the standard?
Asserting that something can be computed at compile-time is a pretty strong kind of optimization.
Inlining merely removes a function call, by copy/pasting the function body into the call site. The function body still has to be executed, you just save the overhead of a function call.
But if you make the same code be evaluated at compile-time, it is free at runtime.
But neither inline nor constexpr are primarily about optimization. inline's main purpose is to suppress the one-definition-rule, so that functions can be defined in headers (which is useful for templates, and incidentally, also makes the inlining optimization easier)
And constexpr is there because it is useful in metaprogramming, and incidentally, it may help the compiler better optimize the code, by moving more computations to compile-time.
To quote wikipedia:
C++0x will introduce the keyword constexpr, which allows the user to
guarantee that a function or object constructor is a compile-time
constant.
Mark functions inline if they are super short. Mark functions as constexpr if the results are required at compile time. (Template parameters or array sizes). I believe a function can be both if needed.
A constant expression function or constructor can be called with
non-constexpr parameters. Just as a constexpr integer literal can be
assigned to a non-constexpr variable, so too can a constexpr function
be called with non-constexpr parameters, and the results stored in
non-constexpr variables. The keyword only allows for the possibility
of compile-time constancy when all members of an expression are
constexpr.
So, GCC is not incorrect in this.
While inline says to the compiler "This function is used somewhere in this translation unit and is not public to other object files", it is likely that the compiler inserts the body of the function into the caller. constexpr functions say to the compiler "This function has no side effects and does not depend on preconditions other than the parameter itsself."
constexpr variables just say "This variable does not change and its data can be included into the code.". However it makes a difference if you define a constexpr variable in a function static or nonstatic, eg. if a constexpr array is nonstatic, gcc just moves the data with hardcoded mov-instructions onto the stack, while static constexpr just stores the data in the .text-section.
Lambda expressions without capture assigned to a variable can be constexpr other than with capture, because without they need no memory to save the capture and they work like an empty class with overloaded operator() (but they can even be casted to plain function pointers with a simple unary plus: +[]{}).