带有模板成员变量的 C++ 类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13980157/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:52:07  来源:igfitidea点击:

C++ class with template member variable

c++templatestypes

提问by endbegin

I am trying to solve a programming problem that consists of an object (call it Diagram), that contains several parameters. Each parameter (the Parameter class) can be one of several types: int, double, complex, string - to name a few.

我正在尝试解决一个包含多个参数的对象(称为图)的编程问题。每个参数(Parameter 类)可以是以下几种类型之一:int、double、complex、string - 仅举几例。

So my first instinct was to define my Diagram class as having a vector of template parameters, which would look like this.

所以我的第一直觉是将我的 Diagram 类定义为具有模板参数的向量,它看起来像这样。

class Diagram
{
private:
    std::vector<Parameter<T> > v;
};

This doesn't compile, and I understand why. So, based on the recommendations on this page How to declare data members that are objects of any type in a class, I modified my code to look like:

这不能编译,我明白为什么。因此,根据此页面如何声明属于类中任何类型对象的数据成员的建议,我将代码修改为如下所示:

class ParameterBase
{
public:
    virtual void setValue() = 0;
    virtual ~ParameterBase() { }
};


template <typename T>
class Parameter : public ParameterBase
{
public:
    void setValue() // I want this to be 
                    // void setValue(const T & val)
    {
        // I want this to be 
        // value = val;
    }

private:
    T value;
};

class Diagram
{
public:
    std::vector<ParameterBase *> v;
    int type;
};

I'm having trouble figuring out how to call the setValue function with an appropriate templated parameter. It is not possible to have a templated parameter in the ParameterBase abstract base class. Any help is greatly appreciated.

我无法弄清楚如何使用适当的模板化参数调用 setValue 函数。在 ParameterBase 抽象基类中不可能有模板化参数。任何帮助是极大的赞赏。

P.S. I don't have the flexibility to use boost::any.

PS 我没有使用 boost::any 的灵活性。

回答by Mooing Duck

You got very close. I added a few bits because they're handy

你离得很近。我添加了一些,因为它们很方便

class ParameterBase
{
public:
    virtual ~ParameterBase() {}
    template<class T> const T& get() const; //to be implimented after Parameter
    template<class T, class U> void setValue(const U& rhs); //to be implimented after Parameter
};

template <typename T>
class Parameter : public ParameterBase
{
public:
    Parameter(const T& rhs) :value(rhs) {}
    const T& get() const {return value;}
    void setValue(const T& rhs) {value=rhs;}    
private:
    T value;
};

//Here's the trick: dynamic_cast rather than virtual
template<class T> const T& ParameterBase::get() const
{ return dynamic_cast<const Parameter<T>&>(*this).get(); }
template<class T, class U> void ParameterBase::setValue(const U& rhs)
{ return dynamic_cast<Parameter<T>&>(*this).setValue(rhs); }

class Diagram
{
public:
    std::vector<ParameterBase*> v;
    int type;
};

Diagram can then do stuff like these:

然后图可以做这样的事情:

Parameter<std::string> p1("Hello");
v.push_back(&p1);
std::cout << v[0]->get<std::string>(); //read the string
v[0]->set<std::string>("BANANA"); //set the string to something else
v[0]->get<int>(); //throws a std::bad_cast exception

It looks like your intent is to store resource-owning pointers in the vector. If so, be careful to make Diagramhave the correct destructor, and make it non-copy-constructable, and non-copy-assignable.

看起来您的意图是在向量中存储资源拥有指针。如果是这样,请小心Diagram使用正确的析构函数,并使其不可复制构造和不可复制赋值。

回答by pmr

The bellow implementation uses a few C++11 features but you will be able to pick them apart.

下面的实现使用了一些 C++11 特性,但您将能够将它们分开。

#include <vector>
#include <memory>

class Parameter
{
private:
  class ParameterBase {
  public:
    virtual ~ParameterBase() {}
    virtual ParameterBase* copy() = 0;
    virtual void foo() = 0;
  };

  template <typename T>
  class ParameterModel : public ParameterBase {
  public:
    // take by value so we simply move twice, if movable
    ParameterModel(const T& t) : t(t) {}
    ParameterModel(T&& t) : t(t) {}
    void foo() { t.foo(); }
    ParameterModel* copy() { return new ParameterModel(*this); }
  private:
    T t;
  };

public:
  template <typename T>
  Parameter(T&& t) 
    : pp(new ParameterModel< typename std::remove_reference<T>::type >(std::forward<T>(t))) {}

  // Movable and Copyable only
  Parameter(Parameter&&) = default;
  Parameter& operator=(Parameter&&) = default;

  Parameter(const Parameter& other) : pp(other.pp->copy()) {};
  Parameter operator=(const Parameter& other) {
    pp.reset(other.pp->copy());
    return *this;
  };

  // members

  void foo() { pp->foo(); }
private:
  std::unique_ptr<ParameterBase> pp;
};


class Diagram
{
public:
  std::vector<Parameter> v;
  int type;
};

struct X {
  void foo() {}
};

struct Y {
  void foo() {}
};

int main()
{
  Diagram d;
  d.v.emplace_back(X()); // int

  // parameters are copyable and can be reassigned even with different
  // impls
  Parameter p = d.v.back();

  Parameter other((Y()));
  other = p;
  return 0;
}

What does this code do? It hides the fact that we use inheritance to implement parameters from our users. All they should need to know is that we require a member function called foo. These requirements are expressed in our ParameterBase. You need to identify these requirements and add the to ParameterBase. This is basically a more restrictive boost::any.

这段代码有什么作用?它隐藏了我们使用继承来实现用户参数的事实。他们只需要知道我们需要一个名为foo. 这些要求在我们的ParameterBase. 您需要确定这些要求并将ParameterBase. 这基本上是一个更具限制性的boost::any.

It is also quite close to what is described in Sean Parent's value semanticstalk.

它也非常接近Sean Parent 的值语义谈话中描述的内容。