template<typename T> class Group;
template<typename...U>
class Group<std::tuple<U...>> {
public:
typedef std::tuple<U...> type;
void emplace_back(U&...elem) {
data_.emplace_back(elem...);
}
void emplace_back(U&&...elem) {
data_.emplace_back(elem...);
}
private:
std::vector<type> data_;
};
int main() {
Group<std::tuple<int, std::string>> g;
int e1 = 10;
std::string e2 = "elem2";
g.emplace_back(e1, e2); //OK
g.emplace_back(e1, "elem2"); //error, no instance of overloaded function
return 0;
}
我需要创建一个模板类,在其部分专业化中,使用
std::tuple
创建一个由非 cvr(非 const、非易失性、非引用)普通类型组成的类型列表。该类应使用 std::vector
来存储一系列 std::tuple
类型的元素,其中 std::tuple
中的元素类型与创建的类型列表相匹配。示例代码已经抽象和简化了问题,因此使用 std::tuple
创建类型列表的操作可能看起来很无意义。
向
std::vector
中插入元素时,非模板成员函数会调用 std::vector::emplace_back()
函数。由于是非模板函数,无法实现参数的完美转发;参数包中的所有参数要么统一作为左值引用传递,要么统一作为右值引用传递。
现在,我想知道是否有一种方法可以单独确定每个参数是左值引用还是右值引用,并将它们相应地转发到
std::vector::emplace_back()
函数。
我想到将
Group::emplace_back()
改为模板函数,这样可以完美转发。然而,这会失去类模板的类型参数U
对函数参数的约束,所以我宁愿不使用这种方法。
您有两个明智的选择。移动元素的单个非模板函数:
void emplace_back(U ...elem)
{
data_.emplace_back(std::move(elem)...);
}
或者完美转发的模板
我想到将
改为模板函数,这样可以完美转发。然而,这会失去类模板的类型参数Group::emplace_back()
对函数参数的约束,所以我宁愿不使用这种方法。U
是什么阻止您手动编写约束?
template <typename P> requires (std::constructible_from<U, P &&> && ...)
void emplace_back(P &&... elem)
{
data_.emplace_back(std::forward<P>(elem)...);
}