【问题标题】:Initialize C++ Template Class After it is Declared声明后初始化 C++ 模板类
【发布时间】:2018-08-13 19:25:32
【问题描述】:

我使用template <class T> 创建了一个SinglyLinkedList 模板类。例如,如果我输入“字符串”作为我的命令行参数,我想创建SinglyLinkedList<string>* string_list = new SinglyLinkedList<string>();。如果我输入“数字”作为我的命令行参数,我想创建SinglyLinkedList<string>* number_list = new SinglyLinkedList<string>();。

有没有一种方法可以结合它来做一些事情:

SinglyLinkedList<>* list;
if (argv[0] == "string") {
    list = new SinglyLinkedList<string>();
} else if (argv[1] == "number") {
    list = new SinglyLinkedList<int>();
}

如果我现在这样做,第一行会抛出错误invalid template code。

有没有办法在 C++11 中做到这一点?

【问题讨论】:

  • 多态性。让你的模板类型都继承自一个基类
  • 或使用boost::any 或std::any。请注意,这与您想以相同方式使用 vector&lt;string&gt; 或 vector&lt;int&gt; 没有什么不同。
  • 一个问题是:为这两种类型的列表设置一个变量是否有用?如果你真的想对这些列表的元素做任何有用的事情,你需要再次知道它们的类型。在一种情况下,您需要字符串变量/函数/值,在另一种情况下,int 也是如此。如果您想使用其中包含的元素,那么拥有这样的“通用”列表并没有真正的帮助。
  • @sth 如果我理解正确,我有一个通用 Node 类,它有一个名为 value 的通用变量。请看一下我在 Ken Y-N 的回答下方的第一条评论。
  • @sth 你是说我最好的选择是创建单独的非泛型变量(一个 int 和一个 string)?

标签: c++ eclipse c++11 templates linked-list


【解决方案1】:

如果你把整个列表处理放到一个通用函数中,事情可能会更容易:

template<typename Item>
void process_list() {
  SinglyLinkedList<Item>* list = new SinglyLinkedList<Item>();
  Item it;
  if (std::cin >> it) {
     list->push(it);
  }
}

这样你就可以对Item类型的通用项进行所有处理,并且只需要在调用函数时区分一次类型:

int main(int argc, const char **argv) {
    if (argv[0] == "string") {
        process_list<string>();
    } else if (argv[1] == "number") {
        process_list<int>();
    }
}

【讨论】:

  • 因为我的课程必须使用 C++ 11,所以我认为这是我的最佳答案。我通过使用 argv 让我的问题更容易理解,但我实际上是在使用 ifstream 来输入文件。在 process_list() 方法中,有没有一种方法可以传入非模板变量。例如, void process_list(ifstream in_file)?当我这样做时,我无法使用参数调用该方法。它说“使用未声明的标识符 process_list。”
  • 这是一种特殊多态性的一个例子。如果这就是您所需要的,那么您可能根本不需要模板类,只需 process_int_list() 和 process_string_list()。
  • 对于我正在处理的特定项目,处理字符串和 int 列表日期的代码几乎相同。因此,我只想使用一种方法。是否可以在模板方法中包含非模板参数? @JiveDadson
【解决方案2】:

模板实例化是独立的类,所以没有通用的基类,但是解决这个问题的一种方法是显式定义一个基类:

// Empty base class
class SinglyLinkedBase {};

template <typename T>
class SinglyLinkedList : public SinglyLinkedBase
{
    // As before
};

SinglyLinkedBase* list;
if (argv[0] == "string") {
    list = new SinglyLinkedList<string>();
} else if (argv[1] == "number") {
    list = new SinglyLinkedList<int>();
}

此外,Boost::any 或 std::any(如果您有 C++17 编译器)可能可以在没有虚拟基类的情况下执行此操作。

【讨论】:

  • 所以,我假设我在这里将基类实现为抽象类。如果这样做,如何在基类中设置纯方法,以便可以在 SinglyListList(子)类中使用泛型?现在我有一个通用的 Node 类。如果我创建一个 NodeBase 类,我仍然会遇到 Node 持有一个通用值,即“T _value;”的问题
【解决方案3】:

您正在使用运行时类型确定。

在这种情况下,如果你还想使用同一个变量“list”,它的类型应该是一个抽象基指针。只需使用How do boost::variant and boost::any work? 中显示的“类型擦除”技巧

或者如某某的回答所示,你可能在不同的模板实例化中有两个不同类型的本地版本。

如果要传递非模板参数,记得使用

process_list&lt;string&gt;(in_file) 而不是process_list(in_file)

【讨论】:

    猜你喜欢
    • 2016-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    相关资源
    最近更新 更多