1

Literals don't seem to interplay well with preprocessor macros. For example, I have this preprocessor definition CONFIG_FADE_DELAY_MS that I want to translate to std::chrono::milliseconds. But the ms literal needs to be written close up to it, the the compiler doesn't understand ms when there is a space in between them.

Demo

#include <cstdio>
#include <chrono>

#define CONFIG_FADE_DELAY_MS 5000

using namespace std::chrono_literals;

int main()
{
    // Works
    // const auto tp_now = std::chrono::system_clock::now() + 5000ms;
    // Doesn't work
    const auto tp_now = std::chrono::system_clock::now() + CONFIG_FADE_DELAY_MS ms;
}

I also tried to put parentheses around the preprocessor macro, and put the literal right behind it, but no luck.

Can this be done, or do I need to convert the macro manually?

std::chrono::milliseconds{CONFIG_FADE_DELAY_MS};
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
glades
  • 3,778
  • 1
  • 12
  • 34
  • Why `const`? Try without it. – i486 Mar 02 '23 at 15:45
  • 9
    Can you not just do `#define CONFIG_FADE_DELAY_MS 5000ms`? – xihtyM Mar 02 '23 at 15:47
  • 6
    Does your 5000 need to be a preprocessor define? `static const auto CONFIG_FADE_DELAY = std::chrono::milliseconds{5000};`? – SirGuy Mar 02 '23 at 15:49
  • 2
    This is because of the extra space between the macro and `ms` qualifier. Maybe add `ms` into the macro as well as suggested, it would even make more sense since the macro name explicitly mention "MS". – Fareanor Mar 02 '23 at 15:58
  • @SirGuy even simpler: `static const auto CONFIG_FADE_DELAY = 5000ms;` Just have to move `using namespace std::chrono_literals;` above the declaration – Remy Lebeau Mar 02 '23 at 16:30
  • @xihtyM I would do that but the value is pulled in by [kconfig](https://www.kernel.org/doc/html/next/kbuild/kconfig-language.html) and thus it's not possible. – glades Mar 02 '23 at 16:35
  • 1
    @glades `std::chrono::milliseconds(CONFIG_FADE_DELAY_MS)` will work. Or @Remy Lebeau's answer will work. – xihtyM Mar 02 '23 at 16:40
  • @xihtyM That's what I'm settling for :) – glades Mar 02 '23 at 16:40

2 Answers2

3

You can use the preprocessor's ## token concatenation operator to join the 5000 and ms tokens, eg:

#include <cstdio>
#include <chrono>

#define CONFIG_FADE_DELAY_MS 5000

#define CONCAT2(a, b) a ## b
#define CONCAT(a, b) CONCAT2(a, b)

using namespace std::chrono_literals;

int main()
{
    // Works, translates to:
    // const auto tp_now = std::chrono::system_clock::now() + 5000ms;
    const auto tp_now = std::chrono::system_clock::now() + CONCAT(CONFIG_FADE_DELAY_MS, ms);
}

Demo

The indirection of CONCAT() calling CONCAT2() is required in order for the preprocessor to first translate CONFIG_FADE_DELAY_MS to 5000 before then concatenating ms onto it. If you tried to use simply #define CONCAT(a, b) a ## b then the result would not be 5000ms as expected but rather would be CONFIG_FADE_DELAY_MSms instead, which will obviously fail to compile since CONFIG_FADE_DELAY_MSms is not defined anywhere.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

My solution would be to use std::chrono::milliseconds().

Here is an example:

#include <cstdio>
#include <chrono>

#define CONFIG_FADE_DELAY_MS 5000

int main()
{
    const auto tp_now = std::chrono::system_clock::now() + std::chrono::milliseconds(CONFIG_FADE_DELAY_MS);
}

This simply changes the number from an integer to std::chrono::duration, representing ms. It is also very explicit which is something I like.

xihtyM
  • 240
  • 1
  • 2
  • 9