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

Ski*_*927 4 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];
    }
}
Run Code Online (Sandbox Code Playgroud)

我一直得到同样的错误:

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

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

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

非常感谢您的帮助.我在这里疯了.哈哈.

ken*_*ytm 18

在标头中,您需要提供名称空间.

template<typename T> void printVector(std::vector<T> list);
//                                    ^^^^^
Run Code Online (Sandbox Code Playgroud)

您需要考虑以下几点:

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

    template<typename T> void printVector(std::vector<T>& list);
    //                                                  ^
    
    Run Code Online (Sandbox Code Playgroud)

    但作为参考意味着list内部的修改printVector将被传播出去.您通常不希望不小心修改列表.这可以通过使参数成为一个const蚂蚁来强制执行:

    template<typename T> void printVector(const std::vector<T>& list);
    //                                    ^^^^^
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    #include "Sort_Search.h"
    ...
    #include "Sort_Search.h"
    
    Run Code Online (Sandbox Code Playgroud)

    然后printVector将定义2个副本,这会导致编译器错误.如果两个不同的头a.hb.h包括Sort_Search.h和一些源文件包括a.h和,这是可能的b.h.为了避免这种情况,我们总是需要提供一个#include防护,它可以防止文件被多次包含:

    #ifndef SORT_SEARCH_H_m6f2kyhdncxflxr
    #define SORT_SEARCH_H_m6f2kyhdncxflxr
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    template<typename T> void printVector(const std::vector<T>& list);
    
    #endif
    //^^^^
    
    Run Code Online (Sandbox Code Playgroud)
  3. A 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
    
    Run Code Online (Sandbox Code Playgroud)
  4. 最后,模板的实现方式与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
    
    Run Code Online (Sandbox Code Playgroud)

    或者,如果你还是想分开.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
    
    Run Code Online (Sandbox Code Playgroud)
    // Sort_Search.cpp:
    #include <iostream>
    template<typename T> void printVector(const std::vector<T>& list) {
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

  • @beduin:`std :: vector`不是一个类型.你不能`typedef`它. (2认同)
  • @Skinner927:一个非常大的问题:`using`声明,就像其他一切一样,从标题传播到它所包含的文件,污染命名空间,并可能让包括它在内的人感到惊讶.要理解的关键是C++中的`#include`非常直观:你告诉编译器获取头文件的每个字节,将其转储到cpp文件中,然后编译结果.标头不是单独编译的实体,因此它与您在Java等语言中习惯的库模块的类型完全不同. (2认同)