Literals don't work for preprocessor macros

120 Views Asked by At

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};
2

There are 2 best solutions below

0
Remy Lebeau On

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.

0
xihtyM On

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.