我可以有const参数包吗?

时间:2019-01-21 02:09:29

标签: c++ const c++17 variadic-templates

好的

在一个简单的日志系统上工作很有趣,遇到了一个有趣的问题。我认为能够按照以下方式写点东西会很好:

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上找不到任何相关信息,如果已经在其他地方得到了解答,请原谅我。)

1 个答案:

答案 0 :(得分:4)

当您真正想要的是const引用时,您正在使用转发引用。

args_t&&替换为const args_t&

使用与右值引用相同的语法声明转发引用,并带有双&(因此&&)。一个与另一个的区别在于它是否出现在推导上下文中:推论转发引用,不引用右值引用。换句话说,如果编译器使用您的函数参数来确定模板参数是什么(例如您的情况),则它是转发参考。否则,它是一个右值引用。

在您的情况下,最好使用const引用,因为您明确打算不修改参数。由于您永远都不想通过非const引用来接受参数,因此您不需要完美的转发,使用const引用将为您提供编译器检查的不变性以及接受prvalue的能力。 (例如文字等)。