【发布时间】:2022-10-20 20:59:32
【问题描述】:
我有一个模板类MyClass<T>,它在其构造函数中采用一些包含整数的可迭代(例如T = std::vector<int>)并对其进行处理。
我希望能够将可迭代对象作为临时对象(例如MyClass(std::vector<int>{3,6,9}) 或类似的右值参数)或命名变量(导致左值作为构造函数参数)传递。
我想使用 C++17 模板类推理(即写MyClass(...),而不是MyClass<std::vector<int>>(...))。
我认为我可以将构造函数参数声明为MyClass(T && vec)(“通用引用”)以获取左值或右值(就像我可以使用函数一样),但它给出了错误。似乎T 总是被推断为std::vector<int> 而永远不会std::vector<int>& 与类,而当参数是左值时函数推断std::vector<int>&。
模板构造函数推理和模板函数推理的规则究竟有何不同?我可以避免仅仅为了模板推断而使用包装函数(例如myFunction(T&&vec) { return MyClass<T>(std::forward<T>(vec)); })吗?
在Godbolt 上运行以下代码:
#include <iostream>
#include <utility>
#include <vector>
template <typename T>
using BeginType = decltype(std::declval<T>().begin());
template <typename T>
struct MyClass {
BeginType<T> begin;
BeginType<T> end;
MyClass(T && vec) {
begin = std::forward<T>(vec).begin();
end = std::forward<T>(vec).end();
}
int sum() {
int sum = 0;
for (auto it = begin; it != end; ++it) sum += *it;
return sum;
}
};
template <typename T>
MyClass<T> myFunction(T && vec) {
return MyClass<T>(std::forward<T>(vec));
}
int main() {
std::vector<int> x{1, 2, 3};
std::vector<int> y{2, 4, 6};
// Warmup: Passing r-values works fine
std::cout << MyClass(std::vector<int>{3, 6, 9}).sum() << std::endl; // works fine: T is std::vector<int>
std::cout << MyClass(std::move(y)).sum() << std::endl; // works fine: T is std::vector<int>
// Unexpected: Passing l-values doesn't work
// std::cout << MyClass(x).sum() << std::endl; // error: cannot bind rvalue reference of type 'std::vector<int>&&' to lvalue of type 'std::vector<int>'
// Compare: Passing l-values to function works fine
std::cout << myFunction(x).sum() << std::endl; // works fine: T is std::vector<int>&
}
【问题讨论】:
标签: c++17