【问题标题】:Call function of template class created at runtime运行时创建的模板类的调用函数
【发布时间】:2014-04-24 09:32:05
【问题描述】:

我有一个关于 C++(11) 模板类及其在运行时确定的类型的实例化的棘手问题:

以下场景: 用户使用配置文件(ROS 参数)定义模板类的类型。这仅确定模板类的类型,而不是进一步的逻辑:

类定义:

template<typename T>
class MyClass {
    //[...]
}

示例代码:

/* [Read parameter and write result to bool use_int] */

std::unique_ptr<MyClass> myclassptr {nullptr};
if(use_int) {
    myclassptr.reset(MyClass<int>);
} else {
    myclassptr.reset(MyClass<double>);
}

myclassptr->foobar();

/* [more code making use of myclassptr] */

所以这段代码(当然)是不编译的,因为 unique_ptr 模板也必须与模板类型一起指定。但是,随之而来的问题是模板类型对于使用reset 分配的所有对象必须相同。

一个丑陋的解决方案是将代码 myclassptr-&gt;foobar(); 和以下代码复制到 if/else 的每个分支中,我真的不喜欢。

我希望看到类似这样的解决方案:

/* [Read parameter and write result to bool use_int] */

MyClass<use_int ? int : double> myclass;
myclass.foobar();

到目前为止,我所读到的是,这样的事情也是不可能的。

有人对此有很好的解决方案吗?

【问题讨论】:

  • 也许是一个通用的基类:template &lt;typename T&gt; class MyClass : public IClass;
  • 这就是接口的用途。

标签: c++ class templates c++11 late-binding


【解决方案1】:

最简单的方法是:

class IClass{
  virtual ~IClass {}
  virtual void foobar()=0;
};
template<typename T>
class MyClass:public IClass {
public:
  void foobar() override {
    // code here
  }
};
std::unique_ptr<IClass> myclassptr {};
if(use_int) {
  myclassptr.reset(new MyClass<int>());
} else {
  myclassptr.reset(new MyClass<double>());
}
myclassptr->foobar();

boost::variant 是另一种解决方案,但通常用于不相关的类型。可以进行类型擦除,但通常在您想要对其施加统一接口的不相关类型时再次这样做。

在其他语言中,泛型看起来有点像templates,但实际上是一个带有自动生成类型转换和一些类型检查的抽象接口。 C++ templates 是函数或类编译时工厂。这样的工厂的两个输出在运行时默认是不相关的,你可以根据需要添加这样的关系。

【讨论】:

  • 这看起来是一个不错且干净的解决方案,谢谢!
【解决方案2】:

根据您的需要,您可以将 MyClass 设置为包含 int 或 double 的变体类型,或者您可以使用类型擦除将实现隐藏在接口后面。 Boost.Variant 库可以帮助实现前者。

【讨论】:

  • 感谢使用 Boost.Variant 的想法。它可能正在工作,是我在使用没有默认构造函数的类时遇到问题。此外,当我正确理解了理论后,我需要为每个要调用的函数创建一个访问者类。我不喜欢这种开销或额外的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-06
  • 1970-01-01
  • 2010-12-22
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多