2

I'm designing a logger using a macro. I want to concatenate the incoming log message with a constant string literal. If the log message is given as a string literal, there is no problem. However, if the macro argument is of type const char*, I cannot combine it. The problem is basically below. While solving this problem, I do not want runtime cost like std::string. Because I can concatenate string literals at compile time. I don't want runtime costs because LOG will be printed continuously. How can I solve it?

void foo(const char* msg ) { std::cout << msg << '\n'; } #define TEST(message) foo("hello " message) int main() { TEST("world"); //ok. Output will be hello world. //...codes const char* msg = "message"; TEST(msg); //error } 

I can do it by allocating memory like std::string and filling it into a buffer. But I don't want that.

12
  • 11
    you can't concatenate something with a variable at compile time, because values of variables aren't known at compile time Commented Mar 28, 2023 at 10:55
  • And variadic templates. Commented Mar 28, 2023 at 10:59
  • 2
    You can use a sufficiently-sized static thread-local buffer to format your messages into before outputting. The cost of the I/O is far more than the cost of any copies. And if threads are involved, you must also consider the cost of synchronization. You can avoid dynamic allocation without using tricks like concatenation. Or you can embrace a little bit of dynamic allocation by allowing your static buffer (which could be a std::string) to grow only when necessary. Best of both worlds, in my opinion (and personal experience). Commented Mar 28, 2023 at 11:00
  • 7
    is it actually a "problem" ? or are you trying to optimize something before measuring it? Remember that you can only possibly make something faster when you do already know how much time it takes. I'd be not surprised if it turns out to be insignificant. Though I might be wrong and the only way to know is to measure. Commented Mar 28, 2023 at 11:02
  • 5
    The slowest part of your code would likely be the call to cout, not concatenating a string ... Commented Mar 28, 2023 at 11:05

2 Answers 2

0

You can do it entirely without copying and without the possible performance hit from stream operators:

#include <cstdio> #include <concepts> template <std::same_as<char const*>... T> void foo(T const... msg) { // I recommend choosing a better name for this auto const putsnnl = [](char const* p){ while (*p) std::putc(*p++, stdout); }; (putsnnl(msg),...); std::putc('\n', stdout); } #define TEST(message) foo("hello ",message) 

Instead of concatenating just pass several pointers to const character strings. Unfortunately std::puts prints a newline after the string, so we have to std::putc all characters manually but that's not much different from what puts does, anyway.

Of course, with this you don't need to have macros anymore, unless you are doing something outside the scope of this question that requires macros. Your TEST can just be a free function.


If you want to use std::cout, it is even simpler and even allows you to log things that are not char const* but anything that std::ostream understands:

template <typename... T> void bar(T const&... msg) { (std::cout << ... << msg) << '\n'; } 

(demo)

Sign up to request clarification or add additional context in comments.

5 Comments

The solution looks good. Can I do that in C++17 without concepts?
@EnesAygün I am confused. Was it not a requirement to end up having a single const char * for an API call?
@nielsen I think this was an XY problem.
@EnesAygün Yes, just replace std::same_as<char const*> with typename. You wont have type checking, but that's probably fine.
Thank you all for your help. As you said, that was not a problem. So, the problem was solved.
0

You can't concatenate them without paying some runtime cost but you can pass both strings to foo instead:

void foo(const char* prefix, const char* msg) { std::cout << prefix << msg << '\n'; } #define TEST(message) foo("hello ", message) 

1 Comment

Maybe you'd be interested reading this answer: stackoverflow.com/questions/24783400/… — I tested it and the resulting string is viewed as a literal string at compile time.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.