好的
在一个简单的日志系统上工作很有趣,遇到了一个有趣的问题。我认为能够按照以下方式写点东西会很好:
Log(Info, "Result: {}", value);
给我类似的结果
Result: 45
(在此使用fmt的格式设置样式。)
所以我像这样设置函数:
template <typename ...args_t>
void Log(LogLevel Level, const char* Message, args_t&&... Args)
效果很好,没有问题。但是,我的想法是,如果函数未修改参数,则应将其标记为const(用于优化和作为对程序员的注释),因此我尝试了以下方法:
template <typename ...args_t>
void Log(const LogLevel Level, const char* Message, const args_t&&... Args)
这总是给我错误,VS2017给了我
error C2665: 'Log': none of the 4 overloads could convert all the argument types
我做错了吗?我是否应该担心参数包的一致性?有一个更好的方法吗?有时候,这种参数打包业务很难缠住我的头。
(我花了大约3个小时来研究此问题,但是在堆栈溢出或整个Internet上找不到任何相关信息,如果已经在其他地方得到了解答,请原谅我。)
答案 0 :(得分:4)
当您真正想要的是const引用时,您正在使用转发引用。
将args_t&&
替换为const args_t&
。
使用与右值引用相同的语法声明转发引用,并带有双&
(因此&&
)。一个与另一个的区别在于它是否出现在推导上下文中:推论转发引用,不引用右值引用。换句话说,如果编译器使用您的函数参数来确定模板参数是什么(例如您的情况),则它是转发参考。否则,它是一个右值引用。
在您的情况下,最好使用const
引用,因为您明确打算不修改参数。由于您永远都不想通过非const
引用来接受参数,因此您不需要完美的转发,使用const
引用将为您提供编译器检查的不变性以及接受prvalue的能力。 (例如文字等)。