我正试图了解C++模板和复制语义。我理解为什么我不能调用assign1
(它要求右值引用,而我正在提供一个左值引用(但是,为什么我能够调用assign2
,它施加了相同的约束?
template<typename... Args>
void assign1(Args&& ... arguments) { }
template<typename A, typename... Args>
void assign2(Args&& ... arguments) { }
template<typename A, typename B, typename... Args>
void assign3(Args&& ... arguments) { }
int main() {
const int r = 2;
assign1<int>(r); // no matching function for call to...
assign2<int>(r); // ok!
assign3<int>(r); // no matching function for call to...
}
给定assign1<int>(r);
,您显式指定模板参数,那么assign1
的参数类型将是int&&
,正如您所说,它是右值引用,不能与左值绑定。
给定assign2<int>(r);
,您将第一个模板参数A
指定为int
,参数包Args
将从函数参数r
推导出来。注意,它不是右值引用,而是转发引用,它可以同时接受左值和右值。(根据函数参数是左值还是右值,根据类型推导结果,函数参数类型将是左值引用或右值引用。(
给定assign3<int>(r);
,您只指定了第一个模板参数A
,但第二个参数B
无法从函数参数推导出来,调用失败。
如果你想让函数模板只接受右值,你可以像一样添加static_assert
template<typename A, typename... Args>
void assign2(Args&& ...) {
static_assert(((!std::is_lvalue_reference_v<Args>) && ...), "must be rvalue");
}
实时
或者应用SFINAE。
template<typename A, typename... Args>
std::enable_if_t<((!std::is_lvalue_reference_v<Args>) && ...)> assign2(Args&& ...) {
}
实时
或者添加另一个使用左值引用的重载,并将其标记为delete
。(只有当所有参数都是左值时,这种方法才有效。(
template<typename A, typename... Args>
void assign2(Args& ... arguments) = delete;
实时