0

The compiler says that expression did not evaluate to a constant when I build the following code. But I don't know how to fix the error. Can anybody help?

#include <iostream>
#include <cstring>

const char cstr1[] = "Hello";
const char cstr2[] = "world!";

int main()
{
    constexpr size_t new_size = strlen(cstr1) + strlen(" ") + strlen(cstr2) + 1;
    char cstr3[new_size];

    strcpy(cstr3, cstr1);
    strcat(cstr3, " ");
    strcat(cstr3, cstr2);

    std::cout << cstr3 << std::endl;
}
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Wieshawn
  • 213
  • 1
  • 10

3 Answers3

2

It doesn't work because strlen is not declared constexpr, so the result of it cannot be used in a constexpr.

You could try and get around this by using sizeof, but really you shouldn't be using C-style strings in the first place. C++ has std::string for a reason:

const std::string str1 = "Hello";
const std::string str2 = "world!";

int main(){
    std::string str3 = str1 + ' ' + str2;

    std::cout << str3 << std::endl;
}
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • 4
    Further info for those who are confused by g++ accepting OP's code: g++ [is buggy](http://stackoverflow.com/questions/27744079/is-it-a-conforming-compiler-extension-to-treat-non-constexpr-standard-library-fu) and treats the result of some standard library functions as `constexpr` when in fact they are not, and the Standard explicitly forbids compilers from doing this – M.M Sep 24 '15 at 08:18
  • Thank you for the info @M.M – CinCout Sep 24 '15 at 08:27
1

The standard says that strlen is a genuine function, and isn't known to the compiler what it does, and it's not a constexpr type function (after all, it's exactly the same function being called if you use fgets to read the input from a file or terminal).

Many modern compilers DO understand what strlen does, so the compiler will optimize away the call to the function and replace it with a constant in this type of case. However, it's not required to behave this way in the standard, so whether it works in a particular compiler is entirely up to that particular compiler (and possibly compiler options that enable some type of optimisation!)

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • 1
    It is known to the compiler exactly what `strlen` does: The C++ standard specifies its behaviour. However that is not relevant; what is relevant is that it is not declared `constexpr`. – M.M Sep 24 '15 at 08:39
  • 1
    The C++ standard does not actually specify the behaviour of `strlen()`. It simply says it is declared in `cstring` and otherwise refers to the C standard. In any event, being specified in the C++ standard is not the same as "known to the compiler". Whether the compiler is built with specific handling/optimisation of functions like `strlen()` is a quality of implementation concern, not a requirement of the standards. – Peter Sep 24 '15 at 12:23
  • Nobody said anything about "specific handling/optimization". The effect of `strlen` is to return the number of characters in the string and the compiler knows this. I guess you are thinking something like "the compiler doesn't look in the glibc code" but that doesn't matter at all, C++ is defined in terms of observable behaviour. – M.M Sep 24 '15 at 21:09
  • I _know_ that both gcc and clang (and probably MS compilers) can translate `strlen` from a constant string to a constant. However, the standard does not require this to happen, since `strlen` CAN also be used for non-constant strings, making it a non-constant value. – Mats Petersson Sep 25 '15 at 07:21
0

strlen() is a function that is evaluated at run time, not compile time. Hence the error message. It is inherited from C, so not declared constexpr (which is specific to later versions of C++).

Better to avoid using <cstring> - and arrays of char for that matter - and use the std::string type declared in <string>

#include <iostream>
#include <string>

const std::string cstr1 = "Hello";
const std::string cstr2 = "world!";

int main()
{
    std::string cstr3 = cstr1 + std::string(" ") + cstr2;
    std::cout << cstr3 << std::endl;
}
Peter
  • 35,646
  • 4
  • 32
  • 74
  • `constexpr` integers are integer constant expressions, so `char cstr3[new_size];` is not a VLA. That part of the code is correct. – M.M Sep 24 '15 at 08:28