c++ - 在不同类型的模板化类中创建模板化变量
问题描述
我不确定我所要求的是否可行。
我有一个名为Controller
. 这是一个可变参数模板类,它接受多个类并可以设置它们的值。
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32);
这需要一堆不同的类,并允许我同时设置它们的值。setValues
是一个模板化函数,它允许传入任何类型。但是,现在我正在尝试修改我的类,以便我可以在控制器本身内设置一个值以便于检索。然而,这是被证明是困难的部分。
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){}
Controller(std::tuple<Classes&...> tup) : objects(tup){}
template<typename T>
void setValues(T value)
{
std::apply([&](auto&...x) { x.updateValue(value),...);}, objects); //calls the updateValue function for each class
}
private:
std::tuple<Classes&...> objects;
};
我想将以下内容添加为私有变量T controllerValue;
但是,我知道我不能简单地声明T
,因为我们无法定义成员模板并且编译器不知道会发生什么。然后我尝试创建一个私有结构:
template<typename T>
struct ControllerValue { T value; };
但是,我不能在它下面定义一个结构,因为会发生同样的问题。编译器不知道什么是类型ControllerValue
。我想要的是这样的:
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){}
Controller(std::tuple<Classes&...> tup) : objects(tup){}
template<typename T>
void setValues(T value)
{
thisValue.value = value;
std::apply([&](auto&...x) { x.updateValue(value),...);}, objects); //calls the updateValue function for each class
}
template<typename T>
T getValue() const { return thisValue.value }
private:
std::tuple<Classes&...> objects;
template<typename T>
struct ControllerValue { T value; };
ControllerValue thisValue;
};
ControllerValue
由于编译器不知道应该是什么类型,这根本不会编译。这就是我卡住的地方。这甚至可能吗?如果没有,还有什么方法可以让我完成这项工作?
为了消除混淆,用例将是这样的:
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32);
int commonValue = myController->getValue();
或者
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32.3);
double commonValue = myController->getValue();
解决方案
我认为在 C++ 中解决这个确切的问题是不可能的(在具有运行时泛型的语言中仍然非常麻烦)。您可以非常轻松地创建一个只能存储任何值的多态类:
class PolymorphicBase
{
public:
virtual ~PolymorphicBase() = default;
};
template <class T>
class PolymorphicObject : public PolymorphicBase
{
T value;
public:
PolymorphicObject(T value) : value(std::move(value))
{
}
};
的成员std::unique_ptr<PolymorphicBase>
可以充分存储任何值,但是如何检索这样的值?可能最简单的方法是公开引用PolymorphicBase
并使用动态类型检查来查看类型是否与您知道的内容兼容,但是如果您需要代码适用于任何类型怎么办?
这就是带auto
参数的 lambda 的用途。但是,您必须能够将这样的 lambda 传递给 onPolymorphicBase
方法并在PolymorphicObject
. 这是不可能的,因为您不能覆盖方法模板(它必须是接受 lambda 的模板)——这就是 C++ 的编译时和运行时部分发生冲突的地方。而且在 C++ 中根本没有类型可以表示接受任何参数(并知道其类型)的函数,它本身就是一个模板。
您可以通过使 lambda 的类型为已知来部分解决此问题PolymorphicBase
:
template <class Retriever>
class PolymorphicBase
{
public:
virtual void retrieve(Retriever func) = 0;
virtual ~PolymorphicBase() = default;
};
template <class Retriever, class T>
class PolymorphicObject : public PolymorphicBase<Retriever>
{
T value;
public:
PolymorphicObject(T value) : value(std::move(value))
{
}
void retrieve(Retriever func) override
{
func(value);
}
};
auto lambda = [](auto arg)
{
std::cout << arg << std::endl;
};
PolymorphicObject<decltype(lambda), int> obj(6);
PolymorphicBase<decltype(lambda)> &ptr = obj;
ptr.retrieve(lambda);
如果您只有一种检索值的方法,这将很有用。
无论如何,我认为在大多数情况下都不需要这样做。通常你使用一组固定的类型作为值,所以你可以在那里使用一个变体,或者它们都实现一个公共接口,或者(正如你在评论中指出的那样)你实际上打算将类型参数从类的方法(它允许您检查所有类型是否比最初更早地支持该值)。
但是,我同意在具有泛型/模板的语言中,很难有一种方法可以以泛型方式实际选择其结果类型,而不受外部参数的控制。
推荐阅读
- javascript - setTime 0 在每个视频上结束
- javascript - 如何获得堆叠的内联块 div 以触摸其上方的 div?
- bots - ReferenceError:尝试放置让公会时未定义消息
- r - 如何基于 R 中的 if else 语句创建新列?
- php - 注销获取 PHP 警告:mysqli_query() 需要至少 2 个参数,1 个给定
- tensorflow - 在 TensorflowLite 中转储权重
- python - 运行脚本以发送游戏内泰拉瑞亚服务器命令
- javascript - 使用 Javascript 从 Tik Tok 趋势提要中获取视频列表
- javascript - 如何在javascript中使用嵌套对象展平对象
- gpflow - GPflow - 具有 1 维线性内核的 GP 分类不适合二维数据