有没有办法编写一个宏来仅使用变量名(即相当于 std::forward<T>(t) 的 FWD(t))进行完美转发?

Is there a way to write a macro to do perfect forwarding using only the variable name (i.e. a FWD(t) which is equivalent to std::forward<T>(t))?

我有类似的东西(比方说):

template <typename Collection, typename Item>
void foo_collection(Collection&& c, Item && i) {
    foo(std::forward<Collection>(c), std::forward<Item>(i));
}

我不喜欢 std::forward<Collection>(c) 太长了。相反,我想这样做:

template <typename Collection, typename Item>
void foo_collection(Collection&& c, Item&& i) {
    foo(FWD(c), FWD(i));
}

我想一定有办法使用 decltype 来做到这一点。我想,给定 decltype(i),如果我从中删除所有引用和常量,我会得到 Item,然后它应该可以工作:

#define FWD(v) \
    std::forward< \
        typename std::remove_const<\
        typename std::remove_reference<\
        decltype(v)>::type>::type>(v)

然而,这个doesn't work:

void foo(int& a) { cout << "ref" << endl; }
void foo(const int& a) { cout << "cref" << endl; }

template <typename T>
void call_foo(T&& t) { foo(FWD(t)); }

int main() {
    int a = 10;
    foo(10);      // 1) prints cref
    foo(a);       // 2) prints ref
    call_foo(10); // 3) prints cref
    call_foo(a);  // 4) prints cref
    return 0;
}

为什么 4 调用 cref 重载,而不是 ref 重载?

我试过 #define FWD(a) std::forward<decltype(a)>(a),在这个例子中是 did work。但是,我猜它不会在所有情况下都有效。是这样吗,如果是这样,它在哪些情况下不起作用?

最后,如果后一种方法不起作用,有没有办法以一种有效的方式编写这个宏?

#define FWD(a) std::forward<decltype(a)>(a)

会起作用的。只要 a 是变量的名称,decltype(a) 就是它被声明为的类型,这就是您应该作为其类型参数传递给 forward 的类型。

如果你传入一个表达式,事情会变得很奇怪。但是,我想不出它会失败的情况。

当然这不适用于 forward 的一些更高级的用途。

方法

#define FWD(a) std::forward<decltype(a)>(a)

实际效果如所见here

void foo(int& a) { cout << "lref" << endl; }
void foo(const int& a) { cout << "cref" << endl; }
void foo(int&& a) { cout << "rref" << endl; }

template <typename T>
void call_foo(T&& t) { foo(FWD(t)); }


int main() {
    int a = 10;
    call_foo(10); // 3) prints rref
    call_foo(a);  // 4) prints lref
    return 0;
}