22

这些功能是否等效?

template <class T>
void foo(T && t)
{
    bar(std::forward<T>(t));
}

template <class T>
void foo2(T && t)
{
    bar(std::forward<decltype(t)>(t));
}

template <class T>
void foo3(T && t)
{
    bar(std::forward(t));
}

如果是,我可以始终使用此宏进行完美转发吗?

#define MY_FORWARD(var) std::forward<decltype(var)>(var)

或者只是使用

bar(std::forward(t));

我相信foo2并且foo3是一样的,但是我发现人们总是使用 forward like foo,有什么理由明确写出类型吗?

我理解T并且T&&是两种不同的类型,但我认为std::forward<T>并且std::forward<T&&>总是给出相同的结果?


编辑:

我想使用宏的原因是我想在下面的 C++1y 代码上节省一些输入,我在不同的地方有很多类似的代码

#define XLC_FORWARD_CAPTURE(var) var(std::forward<decltype(var)>(var))
#define XLC_MOVE_CAPTURE(var) var(std::move(var))

template <class T, class U>
auto foo(T && func, U && para )
{
    auto val = // some calculation
    return [XLC_FORWARD_CAPTURE(func),
            XLC_FORWARD_CAPTURE(para),
            XLC_MOVE_CAPTURE(val)](){
              // some code use val
              func(std::forward<U>(para)); 
          };
}
4

2 回答 2

17

这两个函数是等价的吗?

的,它们是等价的。decltype(t)与 相同T&&,并且与 一起使用时,和std::forward之间没有区别TT&&无论是什么T

我可以始终使用此宏进行完美转发吗?

是的你可以。如果你想让你的代码不可读和不可维护,那就这样做吧。但我强烈建议不要这样做。一方面,使用这个宏基本上没有任何收获。另一方面,其他开发人员必须查看定义才能理解它,这可能会导致细微的错误。例如,添加额外的括号将不起作用:

MY_FORWARD((t))

相反,带有的形式decltype是完全有效的。特别是,它是从泛型 lambda 表达式转发参数的首选方式,因为没有显式类型参数:

[](auto&& t) { foobar(std::forward<decltype(t)>(t)); }

我忽略了第 3 个变体std::forward(t),因为它无效。


更新:关于您的示例:您可以对函数模板使用按值调用而不是按引用调用foo。然后你可以使用std::move而不是std::forward. 这为代码添加了两个额外的移动,但没有额外的复制操作。另一方面,代码变得更加简洁:

template <class T, class U>
auto foo(T func, U para)
{
    auto val = // some calculation
    return [func=std::move(func),para=std::move(para),val=std::move(val)] {
        // some code use val
        func(std::move(para)); 
    };
}
于 2014-04-27T08:56:39.023 回答
2

接受的答案并不能完全解决标题中的问题。

宏参数保留表达式的类型。模板中的转发参数没有。这意味着tin foo2(作为转发函数参数)具有类型T&&(因为这是转发模板参数),但是当宏在其他上下文中时,它可能会有所不同。例如:

using T = int;
T a = 42;
T&& t(std::move(a));
foo(MY_FORWARD(t)); // Which foo is instantiated?

注意这里t不是xvalue ,而是lvalue。With std::forward<T>(t),相当于std::forward<int>(t)t将作为左值转发。但是,MY_FORWARD(t)相当于 的std::forward<int&&>(t)witht将作为 xvalue 转发。当您必须处理一些具有右值引用类型的声明变量时(即使它们在语法上看起来相似,也不转发参数),有时需要这种与上下文相关的差异。

于 2018-11-25T14:21:22.073 回答