0

I have a consteval crc32 function that works just fine on compile time. I want this function to be used in another constant inline function.

Here is a code example for a better understanding:

unsigned int consteval strsum(const std::string str) {
    auto n = 0;

    for (int i = 0; i < str.size(); i++) n += str.at(i);

    return n;
}

void _printHash(const unsigned int hash) {
    printf("%d", hash);
}

__forceinline void printHash(const std::string str) {
    _printHash(strsum(str));
}

int main(int argc, char* argv[]) {
    printHash("abc");
}

I want this code to compile to just:

int main(int argc, char* argv[]) {
    _printHash(/* hash constant */);
}

Instead, i get a C7595 error: A call to a consteval function is not a constant expression.

Is there any way to acheive wanted behavior on MSVC?

Artemking4
  • 31
  • 7
  • Have you tried with the `__force_inline` keyword ? – Mechap Oct 24 '21 at 12:51
  • @Mechap tried just now. Did nto change anything. – Artemking4 Oct 24 '21 at 13:27
  • What compiler options do you use when compiling this code ? – Mechap Oct 24 '21 at 13:36
  • @Mechap Defaults: `/JMC /permissive- /ifcOutput "Debug\" /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm- /Od /sdl /Fd"Debug\vc142.pdb" /Zc:inline /fp:precise /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /std:c++20 /FC /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\TestConsole.pch" /diagnostics:column ` – Artemking4 Oct 24 '21 at 14:13
  • Apparentlty, even with `__forceinline`, the compiler can't inline code in all circumstances : _it can't inline a function when the function or its caller is compiled with `/Od` or `/Ob0`_ – Mechap Oct 24 '21 at 14:38
  • @Mechap Well...Even when i set /O1 or /O2, it still does not work. It throws me an error like before. – Artemking4 Oct 24 '21 at 14:48
  • What do you mean by "error like before"? You haven't mentioned any errors in your question. In fact, you haven't actually explained what you believe the problem is with the code shown. Prepare a [mcve], explain what outcome you expect, and what you observe instead. – Igor Tandetnik Oct 24 '21 at 16:36
  • @IgorTandetnik Thanks, done. I had an example but i didnt provide the current result – Artemking4 Oct 24 '21 at 16:45
  • 1
    Your example is not a [mcve]. If nothing else, `crc_table` is an undeclared identifier. Show code that anyone can copy, paste into their compiler, and reproduce the problem. – Igor Tandetnik Oct 24 '21 at 16:46
  • @IgorTandetnik Okay, sure. I have changed the example and removed the crc, replacing it with a string sum. – Artemking4 Oct 24 '21 at 18:49
  • `consteval` means the function is *always* evaluated at compile-time. Calling it with an argument which is not compile-time-constant is thus forbidden. Make the function `constexpr`, make a new function which is not `consteval`, there are many ways to go about it. – Deduplicator Oct 24 '21 at 18:58
  • @Deduplicator sadly, this does not work. I tried to make the caller function constexpr/consteval, but because it calls a runtime function too, it does not work. – Artemking4 Oct 24 '21 at 19:19
  • You tried to make `printHash()` `constexpr`? I meant to make `strsum()` `constexpr` instead of `consteval`. – Deduplicator Oct 24 '21 at 19:48
  • You cannot have a `consteval` function with an `std::string` parameter because it's not a literal type. `constexpr` is not helpful here at all, the result is not a constant expression if the argument isn't, and an `std::string` isn't. Just don't use `std::string` here. – n. m. could be an AI Oct 24 '21 at 20:03

1 Answers1

1

First thing first, you cannot have a consteval function with an std::string parameter because it's not a literal type. Fortunately std::string_view is infinitely better in this application, and you can have

consteval unsigned int strsum(const std::string_view str) {
    auto n = 0;
    for (auto s : str) n += s;
    return n;
}

Sadly, a parameter of a non-consteval function is never a constant expression, and a consteval function cannot call a regular function. So even though you can have strsum, you cannot call it the way you want.

You could call _printHash(strsum("abc")) instead of printHash("abc"), but if this syntax is not acceptable to you, then I'm afraid you don't have a lot of options, other than accepting that the resulting code will loop over a constant string.

A compiler that is not MSVC will do the right thing without needing any constexpr or consteval (or inline for that matter), so the entire thing is compiled to something equivalent to printf("%d", 294) exactly as desired. But MSVC is just not very good at this kind of optimisations.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • You are wrong, std::string is, in fact, constexpr as of c++/20. – Artemking4 Oct 25 '21 at 06:20
  • Types cannot be `constexpr`. Functions and variables may be `constexpr`. In order for a variable to be `constexpr`, it needs to be of a literal type. If a type is literal, it *might* be possible to create a `constexpr` vriable or function returning this type, but there is no guarantee. I don't see a requirement that `std::string` is a literal type in the standard, can you point it out? – n. m. could be an AI Oct 25 '21 at 07:19
  • 1
    Well apparently even if it is literal, MSVC seems to be the only compiler that implements it. – n. m. could be an AI Oct 25 '21 at 07:27