2

如果基于一个或多个类型参数创建类模板,如何在运行时查询这些类型?

例如:

template <typename T>
class Foo {
 public:
  typedef T TypeT;

  Foo() {}

  // assume i is in range
  void set(size_t i, T value) { store[i] = value; }
  T get(size_t i) { return store[i]; }

  void fast_copy(T* dest) { memcpy(dest, store, 100 * size_of(T)); }

  // ugly public data member
  T store[100];
};


void main() {
  Foo<double> fd;
  Foo<int> fi;

  // this is not C++!
  if (fd::TypeT == fi::TypeT) {

    // do a fast copy since the types match
    fd.fast_copy(fi.store);

  } else {

    // do a slower item by copy since the types don't match
    // and let the runtime perform the type conversion:
    for (size_t i = 0; i < 100; ++i) {
      fi.set(i, static_cast<fd::TypeT>(fd.get(i)));
    }
  }
}

我想这样做的原因是因为我有包含浮点数、双精度数或整数数组的运行时对象,我想将它们复制到不同类型的数组中,但我不知道这些类型将是什么它们是在运行时确定的。在上面的示例中,用于实例化 fi 和 fd 的类型是已知的,但在完整示例中,fi 和 fd 将引用多态类,该类可以是任何基本数值类型的数组的容器。

该机制旨在成为一组返回浮点数、双精度或整数数组的函数与另一组需要浮点数、双精度或整数数组的函数之间的运行时可配置桥梁,并且类型可能相同也可能不同桥的两边。桥是不平凡的,它还做了一些其他的事情,但需要将一个类型的数组(或数组的容器)放入其中,并在另一个类型中生成另一种类型的数组 an(或数组的容器)最后,在类型相同和不同的情况下。

注意:这与我的上一个问题有关,如果这个问题更有意义,将替换它。

编辑:这里有更多关于我正在尝试做的事情的信息。

我有一个系统,它的一侧由一组返回数值结果的函数组成。有些返回单个浮点数或双精度数,有些返回单个整数,有些修改(因此“返回”)浮点数、双精度数或整数数组。有一大堆。我想将每一个(实际上,只是返回的数据,函数无关紧要)与我称之为“源”对象的东西相关联——这可能是Source<T>,其中 T 是数字类型。尽管我可能需要SourceScalar<T>SourceVector<T>处理单个值或数组。无论如何,这个对象是“桥”的入口点。每个Source<T>对象存储在 Source 对象的异构集合中,并由唯一的“Source Key”引用。例如,一个这样的与源相关的函数可能会返回一个由 32 个浮点组成的数组,代表波表振荡器的最新输出。另一个可能会返回一个包含 32 个双精度数的数组,表示超过 32 个样本的峰值检测器输出。

在系统的另一端,我还有另一组功能。这些都以数值为参数。有些需要单个浮点数或双精度数,有些需要单个 int,有些需要相同的数组。这些也有一大堆。我有一个我称之为“Dest”对象的东西 -Dest<T>或者可能DestScalar<T>DestVector<T>如上所述。该对象存储了一个与这些函数之一绑定的 std::function 包装器,因此它可以在必要时调用该函数。每个 Dest 对象都存储在 Dest 对象的异构集合中,并由唯一的“Dest Key”引用。例如,一个这样的函数可能是一个数字滤波器,它期望接收大小为 32 的数组,但不是浮点数的双精度数。

现在,在运行时,需要一个更高级别的系统(实际上由用户控制)来任意关联任何 Source 与任何 Dest。用户提供两个键 - source 和 dest - 系统将一侧的数据与另一侧的功能“连接”起来。所以在上面的例子中,它可能会尝试将波表振荡器的 32-float 阵列连接到数字滤波器的 32-double 阵列参数。在任何时候,这种关联也可能会被删除。如果来自峰值检测器的 32-double 阵列连接到数字滤波器的 32-double 阵列参数,那么它会希望传输/复制尽可能快,因为这些阵列属于同一类型。

编辑 2:这是一些可以编译的代码,是我可以构造的最简单的情况,它创建两个 Source 和 Dest 对象的集合,并动态地尝试“连接”它们。前两个调用source_collection[1]->set(...)正常工作,但后两个没有,最终调用 BaseDest 基类成员函数set_item,而不是Dest<T>. 这也使用了 typeid() 如果查询的类型相同则返回静态指针的观察,并比较这些指针的以确定类型匹配。这可能是不安全的,最好只使用枚举。

这一切让我感觉非常可怕——一定有更好的方法吗?

#include <vector>
#include <typeinfo>
#include <cassert>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>

class Source;    // fwd
class BaseDest;  // fwd

typedef boost::shared_ptr<Source>   SourcePtr;
typedef boost::shared_ptr<BaseDest> BaseDestPtr;

// target function that takes an array of doubles
void target_func_vd(double *array, size_t len) {
  for (size_t i = 0; i < len; ++i) {
    assert(array[i] == i);
  }
}

// target function that takes an array of floats
void target_func_vf(float *array, size_t len) {
  for (size_t i = 0; i < len; ++i) {
    assert(array[i] == i);
  }
}

// base class for Dest
class BaseDest {
public:
  BaseDest() {}
  virtual ~BaseDest() {}

  virtual void set(float *array, size_t len)  { /* not implemented, but can't be pure */ };
  virtual void set(double *array, size_t len) { /* not implemented, but can't be pure */ };

  virtual void set_item(size_t index, double item) { /* not implemented, but can't be pure */ };
  virtual void set_item(size_t index, float item) { /* not implemented, but can't be pure */ };
  virtual void finished(size_t len) = 0;

  virtual const std::type_info* get_type_info() const = 0;
private:
};

template <typename T>
class DestVector : public BaseDest {
public:
  typedef boost::function<void (T *, size_t)> Callable;

  explicit DestVector(Callable callable) : callable_(callable) { }

  virtual void set(T *array, size_t len) { callable_(array, len); }
  virtual void set_item(size_t index, T item) { buffer_[index] = item; }
  virtual void finished(size_t len) { callable_(buffer_, len); }

  virtual const std::type_info* get_type_info() const { return &typeid(T); };
private:
  Callable callable_;
  T buffer_[256];
};

// 'set' is overloaded by array type
class Source {
public:
  Source() {}
  void connect(const BaseDestPtr& dest) { dest_ = dest; }

  void set(float *array, size_t len) {
    if (dest_->get_type_info() == &typeid(double)) {
      // convert to double
      for (size_t i = 0; i < len; ++i) {
        dest_->set_item(i, array[i]);  // calls the base member function
      }
      dest_->finished(len);
    } else if (dest_->get_type_info() == &typeid(float)) {
      dest_->set(array, len);
    }
  }

  void set(double *array, size_t len) {
    if (dest_->get_type_info() == &typeid(float)) {
      // convert to float
      for (size_t i = 0; i < len; ++i) {
        dest_->set_item(i, array[i]);  // calls the base member function
      }
      dest_->finished(len);
    } else if (dest_->get_type_info() == &typeid(double)) {
      dest_->set(array, len);
    }
  }

private:
  BaseDestPtr dest_;
};


void main() {

  // test arrays
  float float_array[256];
  for (size_t i = 0; i < 256; ++i) {
    float_array[i] = static_cast<float>(i);
  }

  double double_array[256];
  for (size_t i = 0; i < 256; ++i) {
    double_array[i] = static_cast<double>(i);
  }

  // collection of Sources
  std::vector<SourcePtr> source_collection;

  SourcePtr s0(new Source());
  source_collection.push_back(s0);

  SourcePtr s1(new Source());
  source_collection.push_back(s1);


  // collection of Dests
  std::vector<BaseDestPtr> dest_collection;

  BaseDestPtr t0(new DestVector<float>(&target_func_vf));
  dest_collection.push_back(t0);

  BaseDestPtr t1(new DestVector<double>(&target_func_vd));
  dest_collection.push_back(t1);


  // create and invoke connections
  source_collection[0]->connect(dest_collection[0]);
  source_collection[0]->set(float_array, 256);  // this should end up passing float_array to target_func_vf, and it does

  source_collection[0]->connect(dest_collection[1]);
  source_collection[0]->set(double_array, 256); // this should end up passing double_array to target_func_vd, and it does

  source_collection[1]->connect(dest_collection[0]);
  source_collection[1]->set(double_array, 256); // this should end up passing double_array to target_func_vf, but it doesn't

  source_collection[1]->connect(dest_collection[1]);
  source_collection[1]->set(float_array, 256); // this should end up passing float_array to target_func_vd, but it doesn't
}
4

1 回答 1

0

您可以使用重载。将此添加到您的班级

void copy(T & dest)
{
   fast_copy(&dest):
}

template<class U>
void copy(U & dest)
{
   for (size_t i = 0; i < 100; ++i) {
      dest.set(i, static_cast<TypeT>(get(i)));
}

PS:更多的c++方式是定义copy-constructor或者assignment operator

编辑:如果你想要动态 mke 的东西更多态

struct BaseDest
{
   virtual void assign(const double * v, size_t cnt) = 0;
   virtual void assign(const float * v, size_t cnt) = 0;
//etc
}

template<class T>
struct DestImpl
{
   void assign(const double * v, size_t cnt)
   {
       assign_impl(v, cnt);
   }
   void assign(const float * v, size_t cnt)
   {
       assign_impl(v, cnt);
   }

   template<class U>
   void assign_impl(const U * v, size_t cnt)
   {
      for (size_t i = 0; i < cnt; ++i) {
         set(i, static_cast<T>(v[i])));
   }

   template<>
   void assign_impl<T>(const T * v, size_t cnt)
   {
      fast_copy(v, cnt);
   }
//stuff
}

struct Source
{
//blah
   template<class T>
   void set(const T * v, size_t cnt)
   {
     dest_->set(v, cnt);
   }

//blah
}
于 2013-03-25T09:16:39.933 回答