I have a dumb constexpr version of strlen and the compiler accepts it as constexpr in some cases, but in others it does not, here's an example:
template <std::size_t MAX_SIZE>
class FixedString
{
public:
explicit FixedString(const char* str)
{
for(std::size_t i = 0; i < MAX_SIZE; i++)
{
data[i] = str[i];
}
}
char data[MAX_SIZE];
};
constexpr std::size_t constexpr_strlen(const char *str)
{
for(std::size_t i = 0; i < std::numeric_limits<std::size_t>::max(); i++)
{
if(str[i] == '\0')
{
return i;
}
}
return 0;
}
// doesn't compile, compiler says non-type template argument is not a constant expression
auto make_string(const char* str)
{
return FixedString<constexpr_strlen(str)>(str);
}
int main()
{
constexpr bool IS_DEV = true;
// works fine
std::array<int, constexpr_strlen(IS_DEV ? "Development" : "Production")> arr;
// works fine
FixedString<constexpr_strlen(IS_DEV ? "Development" : "Production")> str("Develop");
// doesn't compile, compiler says variable has incomplete type 'void'
auto string = make_string("Not working");
return 1;
}
Why is it that constexpr_strlen is considered constexpr out of the make_string function and in it's not?
For what I can see here, it can be computed at compile time, can't it?
The main problem is that constexpr functions are by definition intended to be callable at compile-time as well as at run-time. Let's start with a simpler example:
constexpr int f(int n) { return n };
int n = 7;
// n could be modified!
f(n); // compiler cannot know which value n has at runtime,
// so the function needs to be executed at runtime as well!
f(7); // well, now right the opposite...
So it's quite simple: The result of a constexpr function is constexpr, too, if and only if all the arguments the function is called with are constexpr themselves (and only then, the function is evaluated at compile-time), otherwise, it will be a runtime value (and the function is evaluated at run-time).
Inside constexpr functions, though, the compiler cannot know if the function is called with constexpr arguments only or not; so function parameters always need to be considered non-constexpr. And here we are...
(Sure, make_string isn't even constexpr, but if constexpr cannot be assumed for parameters of constexpr functions, then even less for normal function parameters...)
Related
I have the following code:
constexpr uint32_t countWords(const char* str) {
constexpr std::size_t length = std::char_traits<char>::length(str);
std::uint32_t count = 0;
for (std::size_t i = 0; i < length; i++) {
if (str[i] == ' ') {
count++;
}
}
return count;
}
My problem arises on the first line of the function where I get a syntax error stating that:
str cannot be used as a constant
when I try to pass it to std::char_traits<char>::length. If I remove the constexpr from the length variable the error goes away, but to me that implies that the variable is not obtainable at compile time which defeats the purpose of the constexpr function. I plant call this functions using string literals as the parameter.
std::char_traits::length
From the comments it seems you are interested in using this on string literals.
All you need to do to make that work is to remove constexpr from length.
The function has to be callable at run-time as well as compile-time.
But when you call it with a string literal it can be calculated at compile time. You can verify this by assigning the return value of the function to a constexpr variable.
#include <iostream>
#include <string>
constexpr uint32_t countWords(const char* str) {
std::size_t length = std::char_traits<char>::length(str);
std::uint32_t count = 0;
for (std::size_t i = 0; i < length; i++) {
if (str[i] == ' ') {
count++;
}
}
return count;
}
int main()
{
constexpr auto wordcount = countWords("This is a sentence");
std::cout << wordcount;
}
First, you need to make your compiler know that the length will be calculated at compile-time. With your current implementation, str parameter could be passed to the function call at both compile time and runtime (if you didn't know, constexpr is not forced to be compile time, it can be executed at runtime too; check for consteval from C++20 which forces compile time calculation).
So, in order to make sure your str variable is passed at compile time, you may want to pass it as non-type template parameter like:
template <char const * S>
constexpr uint32_t countWords() {
constexpr std::size_t length = std::char_traits<char>::length(S);
std::uint32_t count = 0;
for (std::size_t i = 0; i < length; i++) {
if (S[i] == ' ') {
count++;
}
}
return count;
}
but, please note, that this will work only if your S pointer has static storage, so following would work:
static constexpr char str[]{ "a b c" };
constexpr auto cnt = countWords<str>();
but following would NOT work:
constexpr char str[]{ "a b c" };
constexpr auto cnt = countWords<str>(); // ERROR
For more info, please refer to this question here.
Apart of this, your countWords function does not do the right thing because the above example will set variable cnt to value 2 which is not right.
EDIT:
If you want to use function on string literals, then the other answer describes the fix.
Here is my code:
#include <string.h>
#include <stdlib.h>
template <int ...I>
class MetaString
{
char buffer_[sizeof...(I)+1];
public:
// A constexpr constructor
constexpr MetaString(const char * arg) :buffer_{ encrypt(arg[I])... }
{}
constexpr const char *get()const { return buffer_; }
private:
constexpr char encrypt(const char c) const { return c ^ 0x55; }
};
char *decrypt(const char* buffer_, int size)
{
char* tmp = (char *)malloc(size + 1);
strcpy_s(tmp, size + 10, buffer_);
for (int i = 0; i < size; i++)
{
*(tmp + i) = *(tmp + i) ^ 0x55;
}
return tmp;
}
int main()
{
constexpr MetaString<0,1,2,3,5> var("Post Malone");
char * var1 = decrypt(var.get(), 5);
std::cout << var1 << std::endl;
return 1;
}
The idea is simple, I create object of MetaString and provide some string to it. The constructor encrypts the argument by XOR. Then I have decrypt function which decrypts value back.
The problem is that I set breakpoint in constructor (specifically this line constexpr MetaString(const char * arg) :buffer_{ encrypt(arg[I])... }) and it is hit when I run in debugging mode. Which as I understand means that the constructor is called during runtime.
To guarantee that functions be evaluated at compile time I created object this way constexpr MetaString<0,1,2,3,5> var("Post Malone"); But I've read that constexpr variable must be literal type.
So my question is how can I manage to have variable like var (which would have encrypted data in it and be evaluated at compilation time) and then call decrypt at runtime and get original value?
constexpr only guarantees that a function or variable can be used in a constant expression. It does not guarantee that a function/object is going to always be evaluated/constructed at compiletime. In your particular case, that's actually not really possible since we're talking about an object with automatic storage duration. The object, if it is going to be created, can only really be created when the program is running. Try making your variable static…
I'm not sure why the array creation in the function passes but not the one in the class even though array size is a compile time computable value.
template<int N>
int getPow()
{
int power = 1;
while(power < N)
power <<= 1;
return power;
}
template<int N>
class Test
{
private:
int data[getPow<N>()];
};
void testfun()
{
int test[getPow<2>()]; // passes
Test<10> t1; // Fails????
}
As getPow is not constexpr, it cannot be used in places which require constant expression (as C-array size).
int test[getPow<2>()]; // passes
. You unfortunately use VLA extension. It should not pass.
You might solve your issue with:
template <unsigned N>
constexpr unsigned getPow()
{
return 1 << N;
}
I am trying to write a constexpr find function that will return the index of a std::array containing a certain value. The function below seems to work OK except when the contained type is const char*:
#include <array>
constexpr auto name1() {
return "name1";
}
constexpr auto name2() {
return "name2";
}
template <class X, class V>
constexpr auto find(X& x, V key) {
std::size_t i = 0;
while(i < x.size()) {
if(x[i] == key) return i;
++i;
}
return i;
}
int main() {
constexpr std::array<const char*, 2> x{{name1(), name2()}};
constexpr auto f1 = find(x, name1()); // this compiles
constexpr auto f2 = find(x, name2()); // this doesn't...
}
The weird thing is that find(x, name1()) compiles cleanly but find(x, name2()) fails with the error:
subexpression not valid in a constant expression
if(x[i] == key) return i; `
How can this expression work when used with name1() but fail when used with name2()?
I have also found this answer, but the user builds the array class from scratch and I do not want to do that.
Seems like a compiler bug. Both f1 and f2 should fail to compile in the same way.
The main issue is that it's an assumption that "name1" == "name1" and "name1" != "name2". The standard in fact provides no such guarantees, see [lex.string]/16:
Whether all string literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.
Even though the assumption most likely holds, comparing unspecified values inside constexpr is expressly not allowed, see [expr.const]/2.23:
— a relational ([expr.rel]) or equality ([expr.eq]) operator where the result is unspecified;
A workaround (and the right thing to do) would be to not rely on addresses of string literals and instead compare the actual strings. For example:
constexpr bool equals(const char* a, const char* b) {
for (std::size_t i = 0; ; ++i) {
if (a[i] != b[i]) return false;
if (a[i] == 0) break;
}
return true;
}
template <class X, class V>
constexpr auto find(X& x, V key) {
std::size_t i = 0;
while(i < x.size()) {
if(equals(x[i], key)) return i;
++i;
}
return i;
}
I'm having trouble with nontype(int variable) template parameter.
Why can't I pass a constant int variable to a function and let the function instantiate the template?
template<int size>
class MyTemplate
{
// do something with size
};
void run(const int j)
{
MyTemplate<j> b; // not fine
}
void main()
{
const int i = 3;
MyTemplate<i> a; // fine;
run(i); // not fine
}
not fine : compiler says, error: 'j' cannot appear in constant-expression
EDIT
This is what I ended up with.
Maybe someone might use it, someone might suggest better way.
enum PRE_SIZE
{
PRE_SIZE_256 = 256,
PRE_SIZE_512 = 512,
PRE_SIZE_1024 = 1024,
};
template<int size>
class SizedPool : public Singleton< SizedPool<size> >
{
public:
SizedPool()
: mPool(size)
{
}
void* Malloc()
{
return mPool.malloc();
}
void Free(void* memoryPtr)
{
mPool.free(memoryPtr);
}
private:
boost::pool<> mPool;
};
template<int size>
void* SizedPoolMalloc()
{
return SizedPool<size>::GetInstance()->Malloc();
}
template<int size>
void SizedPoolFree(void* memoryPtr)
{
SizedPool<size>::GetInstance()->Free(memoryPtr);
}
void* SizedPoolMalloc(int size)
{
if (size <= PRE_SIZE_256)
return SizedPoolMalloc<PRE_SIZE_256>();
else if (size <= PRE_SIZE_512)
return SizedPoolMalloc<PRE_SIZE_512>();
}
void toRun(const int j)
{
SizedPoolMalloc(j);
}
void Test17()
{
const int i = 3;
toRun(i);
}
Because non-type template parameters require values at compile-time. Remember that templates are a compile-time mechanism; templates do not exist in the final executable. Also remember that functions and the passing of arguments to functions are runtime mechanisms. The value of the j parameter in run() will not be known until the program actually runs and invokes the run() function, well past after the compilation stage.
void run(const int j)
{
// The compiler can't know what j is until the program actually runs!
MyTemplate<j> b;
}
const int i = 3;
run(i);
That's why the compiler complains says "'j' cannot appear in constant-expression".
On the other hand, this is fine because the value of i is known at compile-time.
const int i = 3;
// The compiler knows i has the value 3 at this point,
// so we can actually compile this.
MyTemplate<i> a;
You can pass compile-time values to run-time constructs, but not the other way around.
However, you can have your run() function accept a non-type template parameter the same way your MyTemplate template class accepts a non-type template parameter:
template<int j>
void run()
{
MyTemplate<j> b;
}
const int i = 3;
run<i>();
Basically, C++ has two kinds of constants:
const int a = 5;
MyTemplate<a> foo; // OK
const int b = rand();
MyTemplate<b> foo; // Not OK.
The first example is a compile-time constant. In C++ standard speak, it's an Integral Constant Expression (ICE). The second example is a run-time constant. It has the same C++ type (const int) but it's not an ICE.
Your function void run(const int j) is a run-time constant. You could even pass in user input. Therefore it's not a valid template argument.
The reason for the rule is that the compiler must generate code based on the template argument value. It can't do so if it doesn't have a compile-time constant.
Because j should be known at compile time. In your example it is not.