Reputation: 112
Alright so
Working on a simple logging system for the fun of it, came across an interesting issue. I thought it would be nice to be able to write something along the lines of:
Log(Info, "Result: {}", value);
To give me a result like
Result: 45
(Using fmt's formatting style here.)
So I set up the function like so:
template <typename ...args_t>
void Log(LogLevel Level, const char* Message, args_t&&... Args)
Works great, no problems there. However, I'm of the mindset that if an argument isn't modified by the function, it should be marked as const (for optimization and as a note to the programmer), so I tried this:
template <typename ...args_t>
void Log(const LogLevel Level, const char* Message, const args_t&&... Args)
This keeps giving me errors, VS2017 gives me
error C2665: 'Log': none of the 4 overloads could convert all the argument types
Am I just doing this wrong? Should I not worry about parameter pack const-ness? Is there a better way to do this? This parameter packing business is difficult to wrap my head around sometimes.
(I spent about 3 hours looking into this and couldn't find any relevant information on stack overflow or the internet at large, please forgive me if this has already been answered somewhere else.)
Upvotes: 2
Views: 1117
Reputation: 304
You are using a forwarding reference, when what you really want is a const reference.
Replace args_t&&
with const args_t&
.
A forwarding reference is declared using the same syntax as an rvalue reference, with a double &
(so &&
). What distinguishes one from the other is whether or not it appears in a deduced context: forwarding references are deduced, rvalue references are not. In other words, if the compiler uses your function arguments to figure out what the template parameters are (such as in your case), it's a forwarding reference. Otherwise, it's an rvalue reference.
In your case, a const
reference is preferable because you explicitly intend to not modify the arguments. Since you will never want to accept parameters by non-const
reference, you don't need perfect forward, using a const
reference will get you the compiler-checked immutability as well as the ability to accept prvalues (such as literals, etc).
Upvotes: 6