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?
CodePudding user response:
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.
CodePudding user response:
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.