简体   繁体   English

如何绕过模板虚拟 function 来实现我的目标?

[英]How to bypass template virtual function to attain my goal?

I know this isn't legal C++ due to the compiler not being able to determine how big exactly the vtable is.我知道这是不合法的 C++ 因为编译器无法确定 vtable 到底有多大。 I'm looking for alternatives.我正在寻找替代品。

Basically, I have an abstract base class defining the interface for a set of derived classes.基本上,我有一个抽象基础 class 定义一组派生类的接口。 The return values of some of the functions being exposed through this interface are determined by the input parameter sKeyName.通过此接口公开的一些函数的返回值由输入参数 sKeyName 确定。 My intended code is posted below.我的预期代码发布在下面。

class DataAccess
{ 
    public: 
        template <class T> 
        virtual const Array2D<T>* GetData(std::string sKeyName) const = 0;

        template <class T>  
        virtual Array2D<T>* GetData(std::string sKeyName) = 0; 
}; 

Can somebody give me a workaround to get this functionality?有人可以给我一个解决方法来获得这个功能吗? Any help is appreciated.任何帮助表示赞赏。 Thank you in advance.先感谢您。

What you'd need to do is define a separate, templated interface.您需要做的是定义一个单独的模板化界面。

class DataAccess {
    template<typename T> class InnerInteface {
        virtual Array2d<T>* GetData(std::string) = 0;
    };
};
class OHai : public DataAccess, DataAccess::InnerInterface<float> {
};
int main() {
    DataAccess* D = new OHai;
    if (DataAccess::InnerInterface<float>* data = 
       dynamic_cast<DataAccess::InnerInterface<float>>(D)) {
    }
}

This might get you what you need.可能会为您提供所需的东西。 You can also template the base class, but I'm guessing that's not allowed.您还可以模板化基本 class,但我猜这是不允许的。

You are asking about dynamic functions, but your main problem is not there, but rather here:你问的是动态函数,但你的主要问题不在那里,而是在这里:

The return values of some of the functions being exposed through this interface are determined by the input parameter sKeyName.通过此接口公开的一些函数的返回值由输入参数 sKeyName 确定。

C++ is a statically typed language, and that means that you cannot have a return type for a function that is dependent on the value of the arguments. C++ 是一种静态类型语言,这意味着您不能拥有依赖于 arguments 值的 function 的返回类型。 Ignoring for the time being inheritance, the code that you presented requires the user to determine the type of the array that is being returned independently of the arguments passed:暂时忽略 inheritance,您提供的代码要求用户确定返回的数组的类型,而与传递的 arguments无关

struct SimpleDataAccess {
   template <typename T>
   array2d<T>* get_data( std::string const & which ) {
      return new array2d<T>();
   }
};
int main() {
   SimpleDataAccess accessor;
   array2d<int> = accessor.get<int>( "int" ); // <int> at the place of call fixes
                                              // the return type, not "int" !
}

Now, if you are willing to live with that (ie the caller will know and set the return type) there are different ways of providing workarounds for your particular problem of the language not allowing templated virtual functions.现在,如果您愿意忍受这种情况(即调用者将知道并设置返回类型),则有不同的方法可以为您的语言不允许模板化虚拟函数的特定问题提供解决方法。 The first thing that comes to mind is nice in that it also follows the NVI idiom (and shows its importance): Provide a non-virtual public templated accessor to the data, and implement it in terms of a fixed return type virtual function.想到的第一件事很好,因为它也遵循 NVI 习惯用法(并显示了它的重要性):提供数据的非虚拟公共模板访问器,并根据固定返回类型虚拟 function 实现它。

class DataAccessor {
    virtual Type get_data_impl( std::string const & ) = 0;
public:
    template <typename T>
    array2d<T>* get_data( std::string const & which ) {
       Type tmp = get_data_impl( which );
       return convert( tmp );
    }
};

Assuming that we can resolve what Type and convert are, we have a solution.假设我们可以解决Typeconvert是什么,我们就有了解决方案。 This is a good example of the NVI idiom: the interface offered by users (public, non virtual) differs from the interface required to extensions (private, virtual).这是 NVI 惯用语的一个很好的例子:用户提供的接口(公共的、非虚拟的)与扩展所需的接口(私有的、虚拟的)不同。 The two contracts differ, your users require you to provide a pointer to specific concrete array2d instantiation, but the language does not allow you to require that same contract from your extensions, but that is not a problem because they are different interfaces.这两个合约不同,您的用户要求您提供指向特定具体array2d实例化的指针,但是该语言不允许您从扩展中要求相同的合约,但这不是问题,因为它们是不同的接口。

Now back to Type and convert .现在回到Typeconvert These two are related, and there are different approaches that you can follow.这两者是相关的,您可以采用不同的方法。 The simplest to implement would be having an array2d_base class from which all array2d<T> derive (by providing a virtual destructor you enable RTTI):最简单的实现是拥有一个array2d_base class 从中派生所有array2d<T> (通过提供一个虚拟析构函数来启用 RTTI):

struct array2d_base {
   virtual ~array2d_base() {}
};
template <typename T>
class array2d : public array2d_base {
   // implementation
};
// Type == array2d_base*
// convert == dynamic_cast< array2d<T>* >
template <typename T>
array2d<T>* DataAccessor::get_data( std::string const & s ) {
   return dynamic_cast< array2d<T>* >( get_data_impl( s ) );
}

If you cannot extend or modify the array2d class, then you can achieve a similar result by means of type erasure.如果您无法扩展或修改array2d class,那么您可以通过类型擦除获得类似的结果。 This will have the advantage of not requiring RTTI in array2d but only in the type erasing support.这将具有在array2d中不需要 RTTI 而仅在类型擦除支持中的优点。 The simplest such implementation would be using boost::any in the inner interface:最简单的实现是在内部接口中使用boost::any

// Type == boost::any
// convert == boost::any_cast< array2d<T>* >
template <typename T>
array2d<T>* DataAccessor::get_data( std::string const & s ) {
   boost::any tmp = get_data_impl(s);
   return boost::any_cast< array2d<T>* >( tmp );
}

Let all your different types, that can be returned from GetData, inherit from a base class and return a pointer to that class.让所有可以从 GetData 返回的不同类型从基础 class 继承并返回指向该 class 的指针。 Example:例子:

class Data {};
class Array2D: public Data{};
class DataAccess
{ 
    public:
        virtual Data* GetData(std::string sKeyName) const = 0;
};

I am not sure if this answers your question, but you can take a look into CRTP .我不确定这是否能回答您的问题,但您可以查看CRTP Then you would do:然后你会这样做:

template< typename T >
struct B
{
  virtual Array2D<T>* GetData(std::string sKeyName) = 0; 
};

struct A : public B< int >
{
  virtual Array2D<int>* GetData(std::string sKeyName)
  {
    // implement
  }
};
  • Template functions cannot be virtual.模板函数不能是虚函数。
  • Array2D needs a template parameter. Array2D需要一个模板参数。 Even if type of template class is default, <> is needed.即使模板类型 class 是默认的,也需要<>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM