2

我有一个带有可变数量的模板化参数的模板化类。在这些情况下(我买不起 C++11),一个好的做法是创建一个我们调用的默认类none并将其设置为默认类,如下所示。

struct none {};

template<class T1=none, T2=none, T3=none>
class A{

   template<class T>
   double extract() { return none();}

   template<>
   double extract<T1>() { return m1_();}

   template<>
   double extract<T2>() { return m2_();}

   template<>
   double extract<T3> () { return m3_();}

   T1 m1_;
   T2 m2_;
   T3 m3_;
};

在这个阶段,我不知道如何实现可以访问每个模板化参数的通用/模板化访问器函数。

所有的模板化参数都是不同的,所以我为每个模板化参数专门化了 A::extract()。

有没有更好的方法来做到这一点?我可以看看任何类型的标签吗?

4

4 回答 4

0
struct none {};

template <class T, class N>
class Holder : public N
{
  protected:
    T m;
    typedef Holder<T, N> First;
    double extractP(T*) { return m(); }
    template <class X> double extractP(X*) {
      return this->N::extractP(static_cast<X*>(0));
    }
};

template <class T>
class Holder<T, none>
{
  protected:
    T m;
    typedef Holder<T, none> First;
    double extractP(T*) { return m(); }
    template <class X> none extractP(X*) {
      return none();
    }
};



template <class T1 = none, class T2 = none, class T3 = none>
class A : Holder<T1, Holder<T2, Holder<T3, none> > >
{
  public:
    template <class T> double extract() {
      return this->extractP(static_cast<T*>(0));
    }
};
于 2014-06-22T10:54:46.020 回答
0

您的课程似乎模仿std::tuple,不幸的是,它是在 C++11 中添加的。好消息是您可以boost::tuple改用它。

作为使用示例:

boost::tuple<std::string, double> t = boost::make_tuple("John Doe", 4.815162342);
std::cout << boost::get<0>(t) << '\n';
std::cout << boost::get<1>(t) << '\n';

Live demo

于 2014-06-22T13:07:06.227 回答
0

如果不能访问 C++11,它会有点难看,但您可以利用 Boost.Tuple:

#include <iostream>
#include <boost/tuple/tuple.hpp>

template <size_t I, typename T, typename U>
struct AccessImpl;

template <size_t I, typename T, typename U>
struct AccessImpl {
    template <typename Tuple>
    static T& impl(Tuple& tuple) {
        typedef typename ::boost::tuples::element<I+1, Tuple>::type Next;
        return AccessImpl<I+1, T, Next>::impl(tuple);
    }
};

template <size_t I, typename T>
struct AccessImpl<I, T, T> {
    template <typename Tuple>
    static T& impl(Tuple& tuple) { return boost::get<I>(tuple); }
};

template <typename T, typename Tuple>
T& access(Tuple& tuple) {
    typedef typename ::boost::tuples::element<0, Tuple>::type Head;
    return AccessImpl<0, T, Head>::impl(tuple);
}

int main() {
    boost::tuples::tuple<char, int, std::string> example('a', 1, "Hello, World!");
    std::cout << access<std::string>(example) << "\n";
    return 0;
}

正如预期的那样,这将打印“Hello,World!” .

于 2014-06-22T13:07:14.000 回答
0

与 nm 类似的解决方案,但更多的是 Boost 的Variant类设计。

建议是使用Variant容器(对象的通用容器)并直接在它们上使用访问器。

#include <iostream>
#include <stdexcept>
using namespace std;


class BaseHolder
{
public:
  virtual ~BaseHolder(){}
  virtual BaseHolder* clone() const = 0;
};

template<typename T>
class HoldData : public BaseHolder
{
public:
  HoldData(const T& t_) : t(t_){}

  virtual BaseHolder* clone() const {
    return new HoldData<T>(t);
  }

  T getData() {
      return t;
  }

private:
  T t;
};


class Variant
{
public:

  Variant() : data(0) {}

  template<typename T>
  Variant(const T& t) : data(new HoldData<T>(t)){}

  Variant(const Variant& other) : data(other.data ? other.data->clone() : 0) {}
  ~Variant(){delete data;}

  template<typename T>
  T getData() {
      return ((HoldData<T>*)data)->getData();
  }

private:
  BaseHolder* data;

private:
  Variant& operator=(const Variant& other) { return *this;} // Not allowed
};

struct none {};

class Container{
public:
    Container() : m1_(0), m2_(0), m3_(0){}
    ~Container() {
        if(m1_)
            delete m1_;
        if(m2_)
            delete m1_;
        if(m3_)
            delete m1_;
    }

    none extract() { return none();}

    template<typename T>
    void insertM1(T obj) {
        m1_ = new Variant(obj);
    }

    template<typename T>
    T extractM1() {
        if(m1_ != 0)
            return m1_->getData<T>();
        else
            throw std::runtime_error("Element not set");
    }

    // TODO: implement m2 and m3

    Variant *m1_;
    Variant *m2_;
    Variant *m3_;
};

int main() {

    Container obj;

    char M1 = 'Z';
    obj.insertM1(M1);

    char extractedM1 = obj.extractM1<char>();
    cout << extractedM1;

    return 0;
}

http://ideone.com/BaCWSV

于 2014-06-22T11:01:38.227 回答