C ++:Header文件中的模板正在摧毁我

时间:2011-04-23 07:27:09

标签: c++ templates header

我精通Java,但对C ++来说却很陌生。我绝对不会理解什么是错的 -

以下是代码:

// Sort_Search.h
#ifndef SORT_SEARCH_H
#define SORT_SEARCH_H  

using std::vector;

template<typename T> void printVector(vector<T> &list);

#endif



// Sort_Search.cpp

#include <iostream>
#include <vector>

using std::vector;

template<typename T>
void printVector(vector<T> &list) {
    // print every member of the list
    for(int i = 0; i < (int)list.size(); i++) {
        // insert a comma where needed
        if(i != 0)
            cout << ", ";
        cout << list[i];
    }
}

我一直得到同样的错误:

  

sort_search.h(6):错误C2182:'printVector':非法使用'void'类型

     

sort_search.h(6):错误C2998:'int printVector':不能是模板定义

在同一文件中有更多模板导致类似错误。我想如果我能修好一个,我会弄清楚如何解决剩下的问题。我已经尝试过每一件我能想到的事情。

非常感谢你的帮助。我在这里疯了。哈哈。

3 个答案:

答案 0 :(得分:18)

在标题中,您需要提供名称空间。

template<typename T> void printVector(std::vector<T> list);
//                                    ^^^^^

您需要考虑以下几点:

  1. 在C ++中,如果不指定参数(数组除外),则总是作为值类型传递,与Java不同,Java中每个对象都作为引用类型传递。这意味着,如果功能签名为printVector(std::vector<T> list),则在导入printVector时,列表将复制。这通常是不受欢迎的。因此,您需要通过向类型添加&来将其更改为通过引用传递:

    template<typename T> void printVector(std::vector<T>& list);
    //                                                  ^
    

    但将其作为参考意味着listprintVector的修改将被传播出去。您通常不希望不小心修改列表。这可以通过使参数为const ant:

    来实施
    template<typename T> void printVector(const std::vector<T>& list);
    //                                    ^^^^^
    

    (使它成为const-reference也具有可以接受rvalues的优点。)

  2. 与Java不同,在C和C ++中,#include不知道您之前是否包含过标题。 #include只是一种“复制粘贴”机制。这意味着,如果编译器以某种方式看到

    #include "Sort_Search.h"
    ...
    #include "Sort_Search.h"
    

    然后将定义2个printVector副本,这会导致编译器错误。如果两个不同的标头a.hb.h包含Sort_Search.h,而某些源文件包含a.hb.h,则可以执行此操作。为避免这种情况,我们始终需要提供an #include guard,以防止文件被多次包含:

    #ifndef SORT_SEARCH_H_m6f2kyhdncxflxr
    #define SORT_SEARCH_H_m6f2kyhdncxflxr
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    template<typename T> void printVector(const std::vector<T>& list);
    
    #endif
    //^^^^
    
  3. vector<T>不是内置类型,因此您需要#include <vector>让编译器知道此类型的存在。

    #ifndef SORT_SEARCH_H_m6f2kyhdncxflxr
    #define SORT_SEARCH_H_m6f2kyhdncxflxr
    
    #include <vector>
    //^^^^^^^^^^^^^^^
    
    template<typename T> void printVector(const std::vector<T>& list);
    
    #endif
    
  4. 最后,template的实现方式与Java或C#中的泛型不同。它就像一个AST级别的复制粘贴机制。每次调用printVector时,编译器都会确定T是什么(例如,int),然后通过将T替换为int来创建新函数}。

    因此,模板的实现不能与声明分开。或者,实现是 声明的一部分。因此,为了正确起见,必须将printVector移动到标题中:

    #ifndef SORT_SEARCH_H_m6f2kyhdncxflxr
    #define SORT_SEARCH_H_m6f2kyhdncxflxr
    
    #include <vector>
    #include <iostream>
    
    template<typename T> void printVector(const std::vector<T>& list) {
       for (int i = 0; i < list.size(); ++ i) { ... }
    }
    
    #endif
    

    或者,如果您仍想将.cpp.h分开,则可以包含.cpp 中的.h

    #ifndef SORT_SEARCH_H_m6f2kyhdncxflxr
    #define SORT_SEARCH_H_m6f2kyhdncxflxr
    
    #include <vector>
    
    template<typename T> void printVector(const std::vector<T>& list);
    
    #include "Sort_Search.cpp"
    //^^^^^^^^^^^^^^^^^^^^^^^^
    
    #endif
    
    // Sort_Search.cpp:
    #include <iostream>
    template<typename T> void printVector(const std::vector<T>& list) {
        ...
    }
    

答案 1 :(得分:1)

让您的生活更轻松一百万次,并内联定义所有模板函数/类。拥有一个单独的.h和.cpp文件没有任何好处,因为无论如何都需要在编译时包含这些文件,所以除了分解它们之外什么都没有。

答案 2 :(得分:1)

您的示例实际上有什么问题是Sort_Search.h中缺少#include <vector>指令。当然,其他人发表的评论也是正确的。

相关问题