【问题标题】:Problem using templates in C++在 C++ 中使用模板的问题
【发布时间】:2011-04-25 09:47:11
【问题描述】:

我第一次在 C++ 中使用模板,当我尝试编译时遇到了问题。基本上是在尝试创建我自己的各种基本 ArrayList:

.hpp:

#ifndef ARRAYLIST_HPP_
#define ARRAYLIST_HPP_

template <class T>
class ArrayList
{
    private:
        int current, top ;
        T * al ;

    public:
        ArrayList() ;   // default constructor is the only one
};

#endif /* ARRAYLIST_HPP_ */

.cpp:

#include "ArrayList.hpp"

using namespace std ;

//template <class T>
//void memoryAllocator( T * p, int * n ) ; // private helper functions headers

template <class T>
ArrayList<T>::ArrayList()
{
    current = 0 ;
    top = 10 ;
    al = new T[top] ;
}

主要:

#include "ArrayList.hpp"

int main()
{
    ArrayList<int> test ;
}

当我尝试在没有 main 的情况下编译时,它编译得很好,但是,一旦我尝试在 main 中使用它,我就会收到以下错误:

Undefined symbols for architecture x86_64:
  "ArrayList<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::ArrayList()", referenced from:
      _main in Website.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [APProject2] Error 1

任何关于可能是什么问题的想法将不胜感激!

干杯!

【问题讨论】:

标签: c++ templates generics


【解决方案1】:

模板需要声明在标头中定义。

另外:我认为这不是真正的错误。它提到了ArrayList&lt;std::string&gt; 的实例化,我在任何地方都看不到。

This FAQ entry 解释了原因。

【讨论】:

  • 如何在标头中声明模板?这不就是我所做的模板 吗?
  • @elfsareus:这里的template 指的是整个结构(例如template&lt;typename T&gt; class Foo { };)。您需要在与声明相同的文件中给出所有成员函数(或模板函数中的所有函数)的定义。
【解决方案2】:

您需要在 .hpp 文件中包含实现。编译器需要在编译时知道 T 才能生成特化。

【讨论】:

  • 在你的 main 中,你正在实例化 ArrayList。 ArrayList.cpp 没有任何特定的 T 类型,因此编译器无法对它做任何事情。它需要一个类型。因此,如果您将 .cpp 实现放在 .hpp 中,并将 .hpp 包含在 main 中,编译器将为您实例化一个 ArrayList。可以将模板视为需要额外信息(类型)才能编译的模板或不完整的代码。这有意义吗?
  • 嗯,确实有点意思!谢谢!但是,是否仍然无法为声明和实现维护单独的 .hpp 和 .cpp 文件?还是每个使用泛型类型的方法/构造函数的所有实现都必须在头文件中?
  • 不,你不能将任何使用模板参数的代码放在一个普通的 .cpp 中(好吧,你可以,但它不会编译任何东西)。有些人将实现放在 .icpp 中,然后将其包含在 .hpp 的底部,但这只是为了将“声明”保存在单独的文件中。如果实施冗长且难以阅读,这将很有用。但就编译器而言,它是相同的,因为预处理器本质上会合并两个文件。如果您查看 STL 或 Boost,您会发现大多数库都是 100% 的头文件。
  • 知道了!谢谢!附:最后一个快速的问题,因为我已经引起了您的注意…… :) 如何在 c++ 中从 Java 执行以下操作? test.add(new SomeClassName("stuff"));我知道我能做到: SomeClassName temp("stuff") ; test.add( 临时 ) ;但这有捷径吗?
  • 这取决于 test.add 的签名,即它期望的参数。假设它 test 是 SomeClass 和 SomeClass::add(const SomeClassName&) 那么你只需要 test.add(SomeClassName("stuff"))。但这真的取决于你想做什么,所以在一个新问题中,一个更完整的 Java 示例可能会更好。
【解决方案3】:

您不能将模板化代码放入单独的 .cpp 文件中...您的构造函数应该位于 ArrayList 标头中。关键是,只有在编译main() 时,编译器才意识到它需要实例化 ArrayList 以及 T 将采用什么类型,因此它需要有可用的代码来进行实例化......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-07
    • 2017-04-09
    • 1970-01-01
    相关资源
    最近更新 更多