I have wrote the following code to get the offset of a tuple element
template<size_t Idx,class T>
constexpr size_t tuple_element_offset() {
return static_cast<size_t>(
reinterpret_cast<char*>(&std::get<Idx>(*reinterpret_cast<T*>(0))) - reinterpret_cast<char*>(0));
}
This is actually similar to the implementation of the offsetof macro.
It looks ugly, but compiles and works fine on gcc-4.6
typedef std::tuple<int,char,long> mytuple;
mytuple var = std::make_tuple(4,'c',1000);
char * ptr = reinterpret_cast<char*>(&var);
long * pt = reinterpret_cast<long*>(ptr+tuple_element_offset<2,mytuple>());
std::cout << *pt << std::endl;
prints "1000".
I don't know too much about constexpr, so my questions are:
Is it legal c++?
More important, why I am allowed to call
std::get (which is non constexpr)
inside a constexpr function?
As far as I understand constexpr, the compiler is forced to evaluate the result
of the expression at compile time, so no zero-dereferentiation can occurs in practice.
Is it legal C++?
If by "legal" you mean "well-formed," then, yes.
If by "legal" you mean "valid and will work on any compiler and Standard Library implementation, then, no, because std::tuple is not POD.
Why I am allowed to call std::get (which is not constexpr) inside a constexpr function?
Basically, a constexpr function doesn't necessarily have to consist of just a constant expression. If you tried to use your tuple_element_offset() function in a constant expression, you'd get a compilation error.
The idea is that a function might be usable in a constant expression in some circumstances but not in others, so there isn't a restriction that a constexpr function must always be usable in a constant expression (since there isn't such a restriction, it's also possible that a particular constexpr function might never be usable in a constant expression, as is the case with your function).
The C++0x draft has a good example (from 5.19/2):
constexpr const int* addr(const int& ir) { return &ir; } // OK
// OK: (const int*)&(const int&)x is an address contant expression
static const int x = 5;
constexpr const int* xp = addr(x);
// Error, initializer for constexpr variable not a constant expression;
// (const int*)&(const int&)5 is not a constant expression because it takes
// the address of a temporary
constexpr const int* tp = addr(5);
Related
My question is why the following code is valid C++:
#include <iostream>
#include <tuple>
#include <type_traits>
std::tuple<const char *, const char *> tuple("Hello", "world");
std::integral_constant<std::size_t, 0> zero;
std::integral_constant<std::size_t, 1> one;
template<typename T> const char *
lookup(T n)
{
// I would expect to have to write this:
// return std::get<decltype(n)::value>(tuple);
// But actually this works:
return std::get<n>(tuple);
}
int
main()
{
std::cout << lookup(zero) << " " << lookup(one) << std::endl;
}
Of course, I'm happy to be able to program this way. Moreover, I understand that std::integral_constant has a constexpr conversion operator. However, the parameter n to lookup is not constexpr, so I'm confused as to how a non-static method on a non-constexpr object (even if the method itself is constexpr) can possibly return a compile-time constant.
Of course, we happen to know in this case that the body of the conversion operator doesn't look at the runtime value, but nothing in the type signature guarantees that. For example, the following type obviously doesn't work, even though it, too, has a constexpr conversion operator:
struct bad_const {
const std::size_t value;
constexpr bad_const(std::size_t v) : value(v) {}
constexpr operator std::size_t() const noexcept { return value; }
};
bad_const badone(1);
Is there some extra property of methods that they are considered differently if they ignore the implicit this argument?
Of course, we happen to know in this case that the body of the conversion operator doesn't look at the runtime value, but nothing in the type signature guarantees that.
Correct. What you are missing is the fact that this doesn't matter.
When a function is called during constant expression evaluation, the compiler checks whether the function is constexpr. If it's not constexpr, then the enclosing evaluation fails to yield a constant expression.
But if it is constexpr, then the compiler executes its body at compile time and checks whether anything in its body disqualifies the enclosing evaluation from being a constant expression.
So in the case of the conversion operator of std::integral_constant, the compiler, executing its body at compile time, sees that it simply returns the value of the template parameter, which is fine.
If the compiler were evaluating a constexpr member function of some other type, which reads a non-const non-static data member of the object (and the object is not constexpr), then the compiler, at that point, would determine that the enclosing evaluation is not a constant expression.
It's a bit upsetting that when you see a function that has been declared constexpr, this tells you nothing about which evaluations of that function yield constant expressions, but that's the way it is.
In std::get<n>() the n needs to be a size_t but you pass a std::integral_constant<...>. So the compiler checks if there is an implicit conversion from one to the other, which attempts to call std::integral_constant<...>::operator size_t(). As it happens that is exactly the operator your std::integral_constant<std::size_t, 0> zero; has. So everything works out fine type wise.
But you asked why this is a compile-time constant: The operator size_t() returns the static constexpr T value = v;. So it doesn't matter if the integral_constant itself is const or not. It has no influence on the returned constant.
Why doesn't defining a variable with auto keyword carry the constexpr'ness of the expression used to initialize it?
As an example, consider the following code:
#include <string_view>
constexpr std::string_view f() { return "hello"; }
static constexpr std::string_view g() {
constexpr auto x = f(); // (*)
return x.substr(1, 3);
}
int foo() { return g().length(); }
With GCC 10.2 and --std=c++20 -fsanitize=undefined -O3, this compiles into:
foo():
mov eax, 3
ret
But if we remove the constexpr on line (*), we would get a 27-line program with a bunch of pointers, a long string constant etc.
Notes:
I marked this question C++20, but I have no reason to believe this behavior is different from C++11's.
This question is not about the example, it is about the general behavior of auto w.r.t. constexprness. The example simply shows that that GCC does not treat x as constexpr if we don't explicitly tell it to.
auto is intended to enable type deduction, not a replacement for "everything useful you would have typed here". constexpr is not a part of an expression's type, and is thus ignored by auto (as opposed to const and volatile, which are part of an expression's type, and are deduced).
But if we remove the constexpr on line (*), we would get a 27-line program with a bunch of pointers, a long string constant etc.
That is a choice for your compiler. It has 100% of the information it needs to make that code go away. The fact that it didn't is not the C++ standard's concern.
This is a "quality of implementation" issue, not a standardization issue. If an implementation won't run as much of your code at compile-time as you desire, you can complain to them about it.
Remember: constexpr isn't meant to be a runtime optimization per-se. It's meant to allow you to write things that you otherwise couldn't write. Like std::get<g()>(some_tuple) or whatever. That code has to run at compile-time, since it's being used in a template parameter.
I'm not asking about some kind of deep deduction, only about the case of the function explicitly being constexpr.
Let's forget for a moment that auto is for type deduction and constexpr is not part of the type system. Let's focus instead on what if auto was supposed to deduce constexpr anyway. So what you want is for auto to only deduce constexpr if <expr> is specifically a function that is designated constexpr.
So let's look at some code:
auto x = constexpr_func();
auto y = constexpr_func() + 5;
auto z = constexpr_func() + constexpr_func();
auto w = constexpr_func_2() + constexpr_func_2();
Which of these variables are constexpr? If what you want is what we had, then x would be constexpr, but y would not. I personally would find this both surprising and annoying.
Worse, if we assume constexpr_func() returns an int, then z is also not constexpr. But if constexpr_func_2() returns a user-defined literal type that has a constexpr operator+, then w would be constexpr.
Isn't that all very weird? So I highly suspect that this is not what you really want.
What you really want is for auto x = <expr>; to deduce constexpr if constexpr auto x = <expr>; would be valid.
But really, that goes back to the original point. If you make a variable constexpr, that should mean you want it to be used in a place where being constexpr is required by some process. Given that fact, deducing constexpr makes no sense, because you should need it to be constexpr lest you get a compile error.
I have a question about compile time functions. I understand that static_assert should work only with types, that can be evaluated/computed at compile time. So it does not work with std::string (yet, no support in gcc10 for constexpr std::string) but will work with std::array(when I know size at compile time). I am watching C++ Weekly from Jason Turner, so this snippet is from this episode https://www.youtube.com/watch?v=INn3xa4pMfg.
The code is here: https://godbolt.org/z/e3WPTP
#include <array>
#include <algorithm>
template<typename Key, typename Value, std::size_t Size>
struct Map final
{
std::array<std::pair<Key, Value>, Size> _data;
[[nodiscard]] constexpr Value getMappedKey(const Key& aKey) const
{
const auto mapIterator = std::ranges::find_if(_data, [&aKey](const auto& pair){ return pair.first == aKey;});
if(mapIterator != _data.end())
{
return mapIterator->second;
}
else
{
throw std::out_of_range("Key is not in the map");
}
}
};
enum class OurEnum
{
OUR_VALUE,
OUR_VALUE2,
OUR_VALUE3
};
enum class TheirEnum
{
THEIR_VALUE,
THEIR_VALUE2,
THEIR_VALUE3
};
// This Fails non constant variable of course
/*
Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
// This fails, it is const, but this does not guarentee that it will be created in compile time
/*
const Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
// This works
/*
constexpr Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
//How come this does not work? Oh i see, missing const because constinit does not apply constness
/*
constinit Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
// Okay, I added const specifier but still this makes static_assert fail because of non-constant condition
// Why?
constinit const Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
int main()
{
static_assert(enumsConverter.getMappedKey(OurEnum::OUR_VALUE) == TheirEnum::THEIR_VALUE);
}
I was playing with this sample and find out, that the static_assert does not work with constinit const initialized map. I commented out every possibility and I would like to explain them.
Map is initialized as non-const variable. I understand that this will not work, it is not constant variable nor compile time initialized
Map is initialized as const variable. This will not work either, even though the variable is constant, it is not guaranteed that it will be created at compile time.
Map is initialized as constexpr variable. This guarantee that the variable will be initialized at compile time. Also it implies constness, so we have compile time const variable. This works correctly. (https://en.cppreference.com/w/cpp/language/constexpr)
Map is initialized as constinit varibale. Now, constinit guarantees, that the expression is zero-intiialized or constant initialized. I initialize with constant so according this variable should be known at compile time (Sets the initial values of the static variables to a compile-time constant. - https://en.cppreference.com/w/cpp/language/constant_initialization) But it does not implies constness, so we have compile-time non-const variable, this static_assert can not work.
Map is initialized as constinit const variable. Now we have compile-time constant variable but static_assert refuses to work. static_assert needs contextually converted constant expression of type bool (https://en.cppreference.com/w/cpp/language/static_assert) which is A converted constant expression of type T is an expression implicitly converted to type T, where the converted expression is a constant expression. Why this does not work?
According to cppInsights, the generated code by compiler is same as for constinit const and constexpr.
Map is initialized as constinit const variable. Now we have compile-time constant variable but static_assert refuses to work
The second claim does not follow from the first. We do not have a compile-time constant variable, therefore the static_assert does not work.
constinit does not make your variable a constexpr variable, it only guarantees that you have constant initialization (hence the name constinit). Indeed, constinit does not even imply const:
constinit std::mutex m;
is a valid and motivating use for constinit, and still allows me to lock and unlock m.
The only way to have a constexpr variable is to declare your variable constexpr (with an unfortunate legacy carve out for integral types declared const, which doesn't apply here). If you want to have a constexpr map, you need to declare your map constexpr.
You are trying to address things from the wrong perspective. You see a variable declared as constinit const. You think that, because the object is non-modifiable, and because it is initialized by a constant expression, that this means that the object is a constant expression.
It's not.
Is its value knowable by the compiler? Absolutely. But that's not how "constant expression" is defined.
Something is a constant expression because the standard says that it is. A variable declared constinit is not a constant expression because the rules don't say that it is. A variable declared const is not a constant expression because the rules don't say that it is (except for certain cases of integers, which predate constexpr). And there's no special rule for the use of both of these markers.
A variable is a constant expression if it is declared constexpr (or one of those const integer exceptions). And only constant expressions can appear in static_assert.
That's the rule.
And there's no reason to have a special case of using constinit const because if you wanted a constant expression... you could have just written constexpr. After all, you might be in some template code where someone gave you a T that just so happens to be const, and you create a constinit T variable somewhere. You didn't ask it to be a constant expression; you just wanted a variable that was statically initialized. That the type just so happened to be const is just happenstance.
Now sure, the compiler is free to do all kinds of special optimizations with this knowledge. But this isn't about what the compiler is allowed to do; it's about what the language means. And if you wanted special meaning from that declaration, you should have said it correctly.
Map is initialized as constinit const variable. ... but static_assert refuses to work. ... Why this does not work?
As you have observed, static_assert needs the expression to be known at compile time.
However, const only implies logical constness, and does not imply that the value is known at compile time (ignoring the case of const integral values initialized with constant expressions).
Similarly, constinit only implies static initialization; again, this does not imply that the value is known at compile time.
From the phrasing of your question, I guess you are expecting that:
const + constinit --> constexpr
But that's not the case. If you want the Map to be usable at compile time (i.e. inside a static_assert, you'll need to make it constexpr).
Is constexpr an indicator for the compiler or does it mandate a behaviour ?
The example at hand is the following :
template<typename T>
std::size_t constexpr getID() { return typeid(T).hash_code(); }
hash_code is a runtime constant, yet this snippet would compile even though a compile time evaluation is requested with constexpr. Only after the return value is used where a compile time constant is expected, would we get noticed that this is not usable as a constexpr function.
So is constexpr a "hint" (much like the inline keyword) or "a binding request" to the compiler ?
Is constexpr a “hint” (like inline) or “a binding request” to the compiler?
It is neither. Forget about when it is evaluated. Everything (with a few minor exceptions, notably involving volatile) is evaluated whenever the compiler deems it necessary to produce the behaviour of the C++ abstract machine. There isn't much else to say about when things are evaluated.
The compiler is free to produce code that evaluates what would be constant expressions at runtime if that doesn't produce a different behaviour. It is free to produce code that evaluates things not marked constexpr at compile-time if it has the smarts.
If not about compile-time vs runtime, what is constexpr about, then?
constexpr allows things to be treated as constant expressions. Anything marked constexpr must have the possibility of producing a constant expression in some way.
In the case of functions, they can be able to produce constant expressions with some arguments but not others. But as long as there is some set of arguments that can result in a constant expression, a function can be marked constexpr. If such a set of arguments is used in a function call, that expression is a constant expression. Does that mean it is evaluated at compile-time? See above. It's evaluated when the compiler deems appropriate. The only thing it means is that you can use it in a context requiring a constant expression.
For variables, either they are constant expressions or not. They have no arguments, so if constexpr they always have to be initialised with constant expressions.
TL;DR: constexpr is about tagging things as being usable in constant expressions, not about deciding when to evaluate them.
With that out of the way, it appears your function template is ill-formed. There is no set of arguments that could result in a constant expression. The standard doesn't require a diagnostic for this, though.
From the C++11 Wiki page:
If a constexpr function or constructor is called with arguments which
aren't constant expressions, the call behaves as if the function were
not constexpr, and the resulting value is not a constant expression.
Likewise, if the expression in the return statement of a constexpr
function does not evaluate to a constant expression for a particular
invocation, the result is not a constant expression.
The constexpr specifier thus expresses the possibility to evaluate something at compile time and is subject to some restrictions when used.
For your particular snippet it seems to me that the C++11 constraint:
exactly one return statement that contains only literal values,
constexpr variables and functions
is not fulfilled, as hash_code is defined to be:
size_t hash_code() const;
In this case the standard draft n3242 says:
For a constexpr function, if no function argument values exist such
that the function invocation substitution would produce a constant
expression (5.19), the program is ill-formed; no diagnostic required.
I believe your example fits here.
constexpr functions can be used to evaluate compile time constants. So it is possible to use it like:
constexpr int func(int a) { return a+2; }
char x[func(10)];
If func is called during runtime, the compiler can evaluate this expression before if possible. But that is not a must but normally done if the input is also const.
It is also important to have constexpr constructors. This is the only chance to get non POD classes constexpr objects.
class Point
{
private:
int x;
int y;
public:
constexpr Point( int _x, int _y) : x(_x), y(_y) {}
constexpr int GetX() const { return x; }
};
constexpr Point p{1,2};
int main()
{
char i[p.GetX()];
return 0;
}
The complete answer to your question has two aspects:
A constexpr function can only be evaluated at compile-time when all
arguments can be evaluated at compile-time. It can still be used as
a normal function which is evaluated at runtime.
An constexpr variable must be initialized with a value evaluated at compile-time.
The compiler has to raise an error if it cannot do this.
You could assign the hash code to a constexpr variable and then get a compiler output:
#include <typeinfo>
#include <array>
template<typename T>
std::size_t constexpr getID() {
return []() {constexpr size_t id = typeid(T).hash_code(); return id;}(); }
int main() {
// both statement generate compiler errors
//std::array<int, typeid(int).hash_code()> a;
//constexpr size_t y = typeid(int).hash_code();
size_t x = getID<int>();
}
#cyberpunk_ is trying to achieve something and made some questions about it but all the chase boils down to this:
Is it possible to build a tool to enforce compile-time evaluation of a constexpr function?
int f(int i) {return i;}
constexpr int g(int i) {return i;}
int main()
{
f(at_compilation(g, 0));
int x = at_compilation(g, 1);
constexpr int y = at_compilation(g, 2);
}
In all situations, at_compilation enforce compilation-time evaluation of g.
at_compilation doesn't need to be in this form.
Requirements
Allow any (numerical native) literal type as input for the constexpr function.
this could also be hardcoded based on the function arguments types.
Allow any (numerical native) literal type as output, which is the result of the constexpr function call.
this could also be hardcoded based on the function return type.
Desirables
Reduced macro usage but don't be afraid of using.
Be general (not type hardcoded).
Support any literal type. At last any numerical native literal type is a requirement.
Related Questions:
When does a constexpr function get evaluated at compile time?
Forcing a constant expression to be evaluated during compile-time?
Passing any function as a template parameter?
Where in the C++11 standard does it specify when a constexpr function can be evaluated during translation?
Answers with relevant code samples:
1
2
3 (this one has an illustrative AT_COMPILATION macro)
All the code samples have limitations regarding the requirements.
A clear explanation for how this is unfeasible in C++ is also a good answer.
I suspect it's impossible based on #K-ballo / #Herb Sutter answer which states "and the result is used in a constant expression as well". This was not part of my former conception about constexpr functions, I firstly thought that just passing literals (or other compile-time input) as arguments would suffice to guarantee (by standard) it to be evaluated at compilation-time.
It's already assumed constexpr function's purpose is that they can fit in constant expression situations when necessary, like in array bounds. That's OK. Given that, this question is about a hack on using them just as a tool for compile time calculation. Whether it's a good or bad thing to do should not matter.
I believe that it's impossible because the compiler is only required to compute values that are used at compile-time, and there is no generic expression that can use every part of a value of class type. Computations that initialize private members might even be impossible to force, as you would depend on a public constexpr member function to use the result.
If you could access the object representation by
static_cast< char const * >( static_cast< void const * >( & const_value ) )
then it would be possible to checksum the result of the computation (and use the result as an integral constant expression), forcing the compiler to perform every calculation that isn't moot. But the cast from void * to char * is disallowed in a constant-expression, and likewise attempting to accomplish the same with a union. Even if it were allowed, if the constructor left one byte uninitialized, using an uninitialized value is also forbidden in a constant-expression.
So, even if C++ had better tools for introspection, it would still be impossible to recover the work performed by a constexpr function in order to artificially use some members but not others.
Just to be clear (even if it repeats the question), there's no reason to want this. The language already requires a check that everything can be computed at compile time, if needed, and the only effect of forcing the compiler to non-lazily compute pure values would be to make it slower and use more memory.
Edit (question was radically altered)
If you have several functions returning scalar type, and want to ensure that some of them work as constant expressions under certain arguments, then write test cases using static_assert.
constexpr int g(int i) {return i;}
int i = 5;
static_assert( g( 3 ) == 0, "failure 1" );
static_assert( g( i ) == 5, "failure 2" );
If you don't want to fix the result values, then discard them. (Unfortunately, GCC may optimize out the non-constant part of such an expression, so you might need to do something more baroque on that platform.
static_assert( g( i ) == 5 || true, "failure only if not constexpr" );
As for encapsulating this into a macro, the other linked questions seem to address a lot. If you want to expand one of those answers or to fix a particular bug, it would be better to explain the bug rather than ask us to read so much literature and start from scratch.
Thanks to C++17 (lambda constexpr, auto template parameter, inline as valid template non-type value) we now have a solution:
//implementation
#include <utility>
template<auto X>
using constant = std::integral_constant<decltype(X), X>;
template<class T>
constexpr auto to_constant(T f) //should use && but clang has a bug that would make +f fail
{
constexpr auto ptr = +f; //uses conversion operator to function pointer
return constant<ptr>{}; //not yet implemented for gcc ("no linkage"), working with clang
}
#define constexpr_arg(...) to_constant([]{ return __VA_ARGS__; })
//userland
template<auto Func>
constexpr void func(constant<Func>)
{
constexpr decltype(auto) x = Func();
static_assert(x == 3.14);
}
int main()
{
func(constexpr_arg(3.14));
}
proof it's working : https://godbolt.org/g/vWbyjE
Also this version doesn't work for all cases (mainly if the argument of the macro uses non-constexpr values but still produce a constexpr result).
For such uses cases : https://godbolt.org/g/DRZ5JM
For a gcc version (so portable for now):
//implementation
template<class T>
struct constant
{
static constexpr decltype(auto) value = T::getPtr()();
};
template<class T>
constexpr auto to_constant(T&& f) //remove the && if you want to be also compatible with clang
{
constexpr auto ptr = +f; //uses conversion operator to function pointer
struct A
{
static constexpr auto getPtr() { return ptr; }
};
return constant<A>{};
}
#define constexpr_arg(...) to_constant([]{ return __VA_ARGS__; })
//userland
template<class Constant>
constexpr void func(Constant&&)
{
static_assert(Constant::value == 3.14);
}
int main()
{
func(constexpr_arg(3.14));
}
https://godbolt.org/g/LBCYfi
Use std::integral_constant:
int x = std::integral_constant<int, g(0)>::value;
f(std::integral_constant<int, g(1)>::value);
This code will not compile if g(n) is not evaluated at compile-time.