16

简化示例代码:

#include <iostream>

template<typename T>
void func(T &x)
{
    std::cout << "non-const " << x << std::endl;
}

template<typename T>
void func(const T &x)
{
    std::cout << "const " << x << std::endl;
}

template<typename ...ARGS>
void proxy(ARGS ...args)
{
    func(args...);
}

int main()
{
    int i = 3;

    func(i);
    func(5);
    func("blah");

    proxy(i);
    proxy(5);
    proxy("blah");
}

预期输出:

non-const 3
const 5
const blah
non-const 3
const 5
const blah

实际输出:

non-const 3
const 5
const blah
non-const 3
non-const 5
non-const blah

因此const,当通过可变参数模板时,函数参数的限定符会以某种方式丢失。为什么?我怎样才能防止这种情况?

PS:使用 GCC 4.5.1 和SUSE 11.4测试

4

2 回答 2

19

您只是偶然发现了转发问题使用完美转发解决了这个问题。

基本上,您需要通过 rvalue-reference 获取参数,并依靠std::forward正确转发它们,同时保持它们的性质:

template<typename ...Args>
void proxy(Args&& ...args)  
{
    func(std::forward<Args>(args)...);
}
于 2012-04-20T12:30:54.203 回答
6

正如 Luc 已经提到的,这是一个转发问题,如何防止它的答案是使用完美转发。但我会在最后尝试解决其他问题:

因此,当通过可变参数模板时,函数参数的 const 限定符会以某种方式丢失。为什么?

这与类型推断有关。忽略您正在使用可变参数模板并考虑最简单的一个参数模板:

template <typename T>
void one_arg_proxy( T arg ) {
   func( arg );
}

在您的通话地点one_arg_proxy( 5 ),即参数是int rvalue。类型推断开始确定类型T应该是什么,并且规则规定Tint,因此调用被转换为one_arg_proxy<int>(5)并且被编译的模板的实例化是:

template <>
void one_arg_proxy<int>( int arg ) {
   func( arg );
}

现在调用 tofunc采用左值参数,因此func采用非常量引用的版本比采用 a 的版本更好(不需要转换)const&,从而产生您得到的结果。这里的问题是,func它不是用 to 的参数调用的proxy,而是用它的内部副本调用proxy的。

于 2012-04-20T13:21:56.767 回答