Wal*_*ltK 1 c++ lvalue rvalue-reference perfect-forwarding c++17
如果我将下面代码中的CLASS更改为0而不是1,它将使用gcc或clang进行编译.但是如果CLASS为1,则两个编译器都会失败(在第二次使用bar时).
#define CLASS 1
#include <utility>
void f(int *a);
template <typename Arg>
#if CLASS
struct bar {
#else
void
#endif
bar(Arg && arg) { f(std::forward<Arg>(arg)); }
#if CLASS
};
#endif
void foo()
{
int dummy;
int *p = &dummy;
#if !CLASS
#define a
#define b
#endif
bar a(p + 0);
bar b(p);
}
Run Code Online (Sandbox Code Playgroud)
作为两个单独的片段,没有条件编译:
失败:
#include <utility>
void f(int *a);
template <typename Arg>
struct bar {
bar(Arg && arg) { f(std::forward<Arg>(arg)); }
};
void foo()
{
int dummy;
int *p = &dummy;
bar a(p + 0);
bar b(p);
}
Run Code Online (Sandbox Code Playgroud)
成功:
#include <utility>
void f(int *a);
template <typename Arg>
void bar(Arg && arg) { f(std::forward<Arg>(arg)); }
void foo()
{
int dummy;
int *p = &dummy;
bar(p + 0);
bar(p);
}
Run Code Online (Sandbox Code Playgroud)
template <typename Arg>
struct bar {
bar(Arg && arg) { f(std::forward<Arg>(arg)); }
};
Run Code Online (Sandbox Code Playgroud)
和
template <typename Arg>
void bar(Arg && arg) { f(std::forward<Arg>(arg)); }
Run Code Online (Sandbox Code Playgroud)
不是一回事.在该功能中,bar您有转发参考.这允许您接受左值(p)或右值(p + 0).
使用结构,bar您不再具有转发引用.它不再是转发引用的原因是因为它不再是函数模板参数. 不知道T&&时只是转发参考T.由于你的T(Args)已知(但不是真的,但它被推断,因此可以知道),这意味着它不再是转发参考.
这意味着你有一个对类模板类型的rvalue引用.这很适合
bar a(p + 0);
Run Code Online (Sandbox Code Playgroud)
因为结果是临时int*(int*&&)但是有
bar b(p);
Run Code Online (Sandbox Code Playgroud)
你有一个int*(int*&)所以你不能将rvalue-reference绑定到那个.
如果你希望类的行为像函数一样,你需要类似的东西
struct bar {
template <typename Arg>
bar(Arg && arg) { f(std::forward<Arg>(arg)); }
};
Run Code Online (Sandbox Code Playgroud)
否则,如果你只需要接受左值和右值,你可以添加重载来处理它
template <typename Arg>
struct bar {
bar(Arg & arg) { f(arg); }
bar(Arg && arg) { f(std::move(arg)); }
};
Run Code Online (Sandbox Code Playgroud)