c++ - 尝试交换可变参数模板类时如何正确重载 operator=?
问题描述
我有一门课,我在其中学习任意数量的课程并将它们存储到std::tuple
. 它是一个可变参数模板类。我已经适当地超载了operator+
操作员,它们按预期工作。但是,现在我试图将一个控制器类分配给另一个。我尝试了以下方法:
template<typename...ClassesR>
auto operator=(const Controller<ClassesR...>& rhs)
{
objects.swap(rhs.getObjects());
return *this;
}
但是,当我编译代码时,我收到错误:“没有匹配的函数用于调用std::tuple<A&,B&>::swap(std::tuple<A&,B&,A&>)
注意:没有已知的参数 1 从std::tuple<A&,B&,A&>
到std::tuple<A&,B&>&
“
简而言之,我正在尝试执行以下操作:
ClassA A(3);
ClassB B(3.4);
ClassC C(4.5f);
Controller<ClassA,ClassB> controllerA(A,B);
Controller<ClassC> controllerB(C);
// thinking about it now, this might be the problem...because controllerA is actually
// Controller<ClassA,ClassB> and not Controller<ClassA,ClassB,ClassA>.
controllerA = controllerA + controllerB;
//or
//controllerA = controllerB;
这是我正在使用的代码:
#ifndef CONTROLLER_HPP
#define CONTROLLER_HPP
#include <functional>
#include <vector>
#include <utility>
#include <any>
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){ }
Controller(std::tuple<Classes&...> tup) : objects(tup){ }
//...a bunch of code that doesn't matter
std::tuple<Classes&...> getObjects() const
{
return objects;
}
template<typename...ClassesR>
auto operator=(const Controller<ClassesR...>& rhs)
{
objects.swap(rhs.getObjects());
return *this;
}
private:
std::tuple<Classes&...> objects;
};
template<typename...ClassesL, typename...ClassesR>
auto operator+(const Controller<ClassesL...>& lhs, const Controller<ClassesR...>& rhs)
{
return Controller(std::tuple_cat(lhs.getObjects(),rhs.getObjects()));
}
template<typename...ClassesL, typename ClassesR>
auto operator+(const Controller<ClassesL...> &lhs, ClassesR rhs)
{
Controller<ClassesR> makeController(rhs);
return Controller(std::tuple_cat(lhs.getObjects(),makeController.getObjects()));
}
template<typename ClassesL, typename...ClassesR>
auto operator+(ClassesL lhs, const Controller<ClassesR...> &rhs)
{
Controller<ClassesL> makeController(lhs);
return Controller(std::tuple_cat(makeController.getObjects(),rhs.getObjects()));
}
#endif // CONTROLLER_HPP
operator=
在这种情况下,超载的正确方法是什么?正如我所指出的,在我写这篇文章时,可能是因为模板类可能是一成不变的。所以Controller<ClassA,ClassB>
不能修改为Controller<ClassA,ClassB,ClassA>
所以也许我需要返回一个新的控制器?
解决方案
在 C++ 中,对象永远不能改变它们的类型,并且类模板的各种特化是不同的、不相关的类型。考虑一个假设std::vector<int*>::operator=(const std::vector<bool>&)
;很明显,这是一个毫无意义的请求,并且默认情况下,限制会延续到任何类模板,即使它没有类型依赖于模板参数的成员。(造成这种情况的一个次要原因是允许特化具有不相关的成员——通过继承或通过显式或部分特化。)
因此,定义一个接受包含类模板的任何特化的赋值运算符模板通常是没有意义的:对于它的数据(对于这种模板的大多数特化),根本无法做任何事情。即使类模板是无状态的,通过这样的定义来削弱类型系统通常也不是一个好主意。
当然,在语法和效率方面,有各种方法可以绕过这些限制。一个(小的)静态类型集合(尤其是类似大小的)可以保存在一个std::variant<…>
(内部是一个联合或字节缓冲区)中;可以在 a 中保存无限的类型集std::any
(除了小对象外,它是指向内部堆分配的类型擦除指针)。
推荐阅读
- excel - Excel 刷新时,Access 前端表单不起作用
- sql-server - 如何根据标志列在两个表中使用外键?
- c++ - C++ 11/14/17 中的指向方法回调?
- icloud - Cloudkit JS - 是否可以在不使用 iCloud 仪表板的情况下动态生成 Api 令牌
- c++ - 如何在继承类中共享结构?
- spotfire - Spotfire 将低于特定数量的数据合并到新类别中
- amazon-web-services - 仅当 lambda 使用 AWS Code Pipeline 发生任何更改时才执行云形成
- php - 在 laravel 上添加自定义字段,其中包含查询构建器的位置
- flutter - 如何在颤动中更改“TabBar”中未选择的标签背景颜色?
- javascript - Angular - 如果时区在 moment() 中不匹配,则显示警报