【问题标题】:vector of template struct模板结构的向量
【发布时间】:2013-09-19 16:49:25
【问题描述】:
using namespace std;
#include <vector>
#include <string>

template <class T>
struct ValNode {
    string id;
    T value;
};

class ValTable {
public:
    ValTable();
    template <class T>
    void add(string,T);
    const bool find(string);
    void remove(string);
private:
    template<class T>
    std::vector<ValNode<T>*> vals;
};

编译器错误:error: data member 'vals' cannot be a member template

我确实尝试在结构中使用 T* 值,但没有成功。 我还没有使用代码中的任何功能。只是试图将它编译成 *.o 文件(也带有 .cpp 文件)。

【问题讨论】:

  • 你不能那样做。 ValTable 必须是模板,否则您必须添加另一个包含向量的模板类。
  • 您希望编译器如何确定T 应该在vals 的声明中是什么?制作整个班级模板。请记住,模板类通常不能在 .cpp 文件中定义,它们必须在标题中内联定义。

标签: c++ templates vector


【解决方案1】:

正如错误所说,变量(包括数据成员)不能是模板;只有类和函数可以。

看起来您希望表能够保存各种不同类型的值,在运行时根据传递给add() 的类型指定。为此,您需要动态类型,C++ 不直接支持这些类型。为此,您可以考虑使用 Boost.AnyBoost.Variant 之类的库。

另一方面,也许您只想在每个表中存储一个类型,而在不同的表中存储不同的类型。在这种情况下,类本身需要是一个模板:

template <typename T>
class ValTable {
public:
    ValTable();
    void add(string,T);
    const bool find(string);
    void remove(string);
private:
    std::vector<ValNode<T>*> vals;
};

【讨论】:

  • 感谢您的解释。是的,动态类型是我一直在寻找的关键字。我想我必须尝试其他方法。感谢您的帮助
  • 顺便说一句,我应该如何实现各种数据类型的符号表一体化?
【解决方案2】:

在 C++ 中,类中可以有模板方法,但不能有模板数据成员。 例如:

template<typename T, int n>
struct FixedVector {
    T x[n];
    FixedVector() {
        for (int i=0; i<n; i++) x[i] = 0;
    }

    template<typename C>
    void copy(const C& container) {
        if (container.size() != n) {
            throw std::runtime_error("Wrong size");
        }
        int j = 0;
        for (typename C::const_iterator i=container.begin(),
                                        e=container.end();
             i!=e;
             ++i)
        {
            x[j++] = *i;
        }
    }
};

使用上面的类,您可以声明FixedVector&lt;int, 5&gt; f 并调用f.copy(v),其中v 可以是例如向量或列表或具有size beginend 的任何内容。 所以FixedVector::copy 是一个模板方法,这意味着编译器将为您将传递给函数的每种不同类型生成它的不同版本。

std::vector<double> y;
y.push_back(3.4); y.push_back(5.6); y.push_back(7.8);

std::list<unsigned char> z;
z.push_back('a'); z.push_back('b'); z.push_back('c');

FixedVector<int, 3> v;
v.copy(y);  // This is ok
v.copy(z);  // This is ok too

C++ 不允许模板数据成员,因为这意味着根据您在特定编译单元中使用的类型数量不同,类大小不同,而这不适用于 C++ 编译模型一次一个单元。

添加方法反而很好,因为它不会影响类大小,并且可以通过避免从不同的编译单元拉取同一方法的多个副本,在链接时修复所有内容。

【讨论】:

    【解决方案3】:

    您必须将ValTable 声明为模板

    template <class T>
    class ValTable{
    public:
        ValTable();
        //template <class T>
        void add(string,T);
        const bool find(string);
        void remove(string);
    private:
        //template<class T>
        std::vector<ValNode<T>*> vals;
    };
    

    【讨论】:

    • 我试图避免这种情况。我正在尝试制作一个包含不同类型数据的表格。这是不允许的
    • @JoesonHwang 很抱歉,您无法避免。
    • @JoesonHwang:这在像 C++ 这样的静态类型语言中很棘手。我的回答建议了一些可能有帮助的库。
    【解决方案4】:

    您将无法做到 ValTable 需要成为模板

    你可以拥有这个:

    template <class T> //Make the class as template
    class ValTable {
    public:
        ValTable();
        template <class X>
        void add(string,X);
        const bool find(string);
        void remove(string);
    private:
        //template<class T>
        std::vector<ValNode<T>*> vals;
    };
    

    【讨论】:

      【解决方案5】:

      您不能拥有模板成员值:每个翻译单元可以访问不同的实例化,从而导致不同的对象布局。您需要以某种方式分解类型。

      标准库按照您对std::locale 的要求做了一些事情:每个std::locale 都存储一组不同类型的对象。这是社会目的,不能直接用于您的目的。

      基本思想是自动将每个使用的类型映射到int,然后使用该int 将类型映射到实例。 vals 成员将成为查找正确实例的函数模板。粗略的轮廓可能如下所示:

      int type_index_alloc() { 
          static std::atomic<int> current(0);
          return ++current;
      }
      template <typename T>
      int type_map() {
          static int rc = type_index_alloc();
      }
      class container {
          struct base { virtual ~base() {} };
          template <typename T>
          struct value: base { T v; };
          std::map<int, std::shared_ptr<base>> vals_;
      public:
          T& vals()  {
              std::shared_ptr<base>& rc(vals_[type_map<T>()]);
              if (!rc) {
                  rc = std::make_shared<value<T>>()); }
              return static_cast<value<T>&>(*rc).v;
          }
      };
      

      这只是试图展示事情是如何设置的:我目前无法访问编译器。此外,代码示例仅提供对 T 类型对象的访问,但可以轻松更改为使用 std::vector&lt;T&gt;

      【讨论】:

        猜你喜欢
        • 2012-03-16
        • 2017-06-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多