Casting templated class to more general specialization

喜夏-厌秋 提交于 2019-12-13 18:37:52

问题


I have a templated class with the template argument the number of dimensions of some datapoints the class shall save. This class has a specialized version MyClass<-1> that allows for dimensions not known at compile time.

How can I cast a specific class (say MyClass<2>) to this more general form?

To be a bit more concrete, here is some artificial example that shows the situation. (I use the Eigen library, but I suppose for the general principle this should not matter)

using namespace Eigen;

template <std::size_t dim>
class MyClass {
  public:
    // Some constructors...

    // A sample function:
    Matrix<double, dim, 1> returnPoint();

    // Some more functions here

  private:
    Matrix<double, dim, 1> point;
}

Now, suppose I have the following code segment:

MyClass<2> *foo;
MyClass<Dynamic> *bar;  // Dynamic is a Eigen constant, being defined as -1

// Do something here

// How to do this:
bar = some_cast<MyClass<Dynamic> *>(foo);

Thinking about the problem I suppose what I want is impossible to archive without actually copying the values of point. Anybody able to prove me wrong or confirm this assumption?


回答1:


It is possible to achieve the casting without actually copying the values but only if you have been careful make it work.

When you instantiate a class template with two different sets of arguments you get two distinct classes that are not related. Unless you specifically define one to inherit from the other, for example:

namespace with_inheritance {

template <class T, long sz>
class vector : public vector<T,-1> {
    typedef vector<T,-1> base_t;
public:
    vector() : base_t (sz) { }
};

template <class T>
class vector<T, -1> {
    T* v_;
    size_t sz_;
public:
    vector(size_t sz) : v_ (new T[sz]), sz_ (sz) { }
    ~vector() { delete [] v_; }
    T& operator[](size_t i)
    {
        if (i >= sz_) throw i;
        return v_[i];
    }
};

} // with_inheritance

So in this case you can cast as in:

namespace wi = with_inheritance;
wi::vector<double, 10> v;
wi::vector<double, -1>* p = &v;
std::cout << (*p)[1] << '\n';

Without the inheritance relationship casting between them will not be permitted. You can, however, use reinterpret_cast to get around the type system when you want to. But you have be very careful that the objects have identical layout and invariants to make sure everthing will work ok. As in:

namespace with_lots_of_care {

template <class T, long sz>
class vector {
    T* v_;
    size_t sz_;
public:
    vector() : v_ (new T[sz]), sz_ (sz) { }
    ~vector() { delete [] v_; }
    T& operator[](size_t i)
    {
        if (i >= sz_) throw i;
        return v_[i];
    }
};

template <class T>
class vector<T, -1> {
    T* v_;
    size_t sz_;
public:
    vector(size_t sz) : v_ (new T[sz]), sz_ (sz) { }
    ~vector() { delete [] v_; }
    T& operator[](size_t i)
    {
        if (i >= sz_) throw i;
        return v_[i];
    }
};

} // with_lots_of_care

And then cast as in:

namespace wc = with_lots_of_care;
wc::vector<double, 10> v;
wc::vector<double, -1>* p = reinterpret_cast<wc::vector<double, -1>*>(&v);
std::cout << (*p)[1] << '\n';


来源:https://stackoverflow.com/questions/13684521/casting-templated-class-to-more-general-specialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!