我的C ++项目完全基于模板,因此我的代码分为不同的头文件(仅限标题的项目)。
但是对于库的用户,我想提供一个头文件("库文件"),他们必须包括使用库。
一种可能性是手动将所有代码复制到一个文件中,但如果项目较大,我想用make
自动创建文件。所以我的想法是设置库文件,我在其中包含所有源文件并使用g++ -E
(只是预处理)处理它。但是预处理器无论如何都会将包含在多个文件(即<string>
)中的内容包含在输出文件中。这导致了多重定义&#39;我使用该库时出错。
那么有可能阻止多次复制,还是有其他方法可以用来实现我的目标来获取一个库文件?
如果您需要一些示例代码来回答问题,请发表评论。
示例:
header.h:
#ifndef CSV_H_
#define CSV_H_
#include <deque>
#include <istream>
#include <string>
using std::deque;
using std::istream;
using std::string;
namespace csv {
template<typename T>
class csv_parser {
private:
deque<T> line;
public:
template<typename S>
friend csv_parser<S>& operator>> (istream& input, csv_parser<S>& parser); //file input stream operator
deque<T>& operator>> (deque<T>& target); //data output operator
deque<T> get_line(); //get parsed line
void set_line(string input); //set line and parse
};
#endif
definition.h:
#include <deque>
#include <istream>
#include <sstream>
#include <string>
#include <algorithm>
#include "../headers/csv.h"
using std::deque;
using std::istream;
using std::stringstream;
using std::string;
using std::getline;
using std::copy;
namespace csv {
template<typename T>
csv_parser<T>& operator>> (istream& input, csv_parser<T>& parser) {
parser.line.clear(); //clear the data
T buffer;
string line;
stringstream converter;
getline(input, line); //get one line from csv file
while (line.size() > 0) { //get field from csv line and delete this segment until
//input line is empty
if (line.find_first_of(",") != -1) { //(not the last segment [one ',' left])
converter << line.substr(0, line.find_first_of(",")); //add segment to converter
converter >> buffer; //convert segment to T type
converter.clear(); //clear flags of converter (normally EOF flag is set
//after converting), so writing in converter is enabled again
parser.line.push_back(buffer); //write segment into data
line.erase(0, line.find_first_of(",")+1); //delete segment from input line
}
else { //(last segment in line)
converter << line.substr(0, line.length()); //get rest of the line
converter >> buffer; //convert segment to T type
converter.clear(); //clear flags of converter (normally EOF flag is set
//after converting), so writing in converter is enabled again
parser.line.push_back(buffer);//write segment into data
line.erase(0, line.length()); //delete rest of input string
}
}
return parser;
}
template<typename T>
void csv_parser<T>::set_line(string input) {
line.clear();
T buffer;
stringstream converter;
while (input.size() > 0) { //get field from input and delete this segment until
//input is empty
if (input.find_first_of(",") != -1) { //(not the last segment [one ',' left])
converter << input.substr(0, input.find_first_of(",")); //add segment to converter
converter >> buffer; //convert segment to T type
converter.clear(); //clear flags of converter (normally EOF flag is set
//after converting), so writing in converter is enabled again
line.push_back(buffer); //write segment into data
input.erase(0, input.find_first_of(",")+1); //delete segment from input
}
else { //(last segment in line)
converter << input.substr(0, input.length()); //get rest of the input
converter >> buffer; //convert segment to T type
converter.clear(); //clear flags of converter (normally EOF flag is set
//after converting), so writing in converter is enabled again
line.push_back(buffer);//write segment into data
input.erase(0, input.length()); //delete rest of input
}
}
}
template<typename T>
deque<T>& csv_parser<T>::operator>>(deque<T>& target) {//write parsed data into target
target.clear();
target.assign(line.begin(), line.end()); //copy data into target
line.clear(); //delete data
return target;
}
template<typename T>
deque<T> csv_parser<T>::get_line(){ //return data
deque<T> buffer = line; //copy data into buffer
line.clear(); //delete data
return buffer; //return buffer
}
}
(未编译)library.h:
#include "header.h"
#include "definition.h"
编译器指令:
g++ -E library.h -o library_out.h
因此,如果我在应用程序中使用library_out.h,则会多次定义符号(即deque标头的一部分)。
答案 0 :(得分:1)
如果您的库只是标题,则必须将所有非模板函数(包括特化)标记为inline
。否则,在多个TU中包含一个标题会导致多个定义链接错误。
示例:
// header.h
inline void f(){}
// p1.cpp
#include "header.h"
// p2.cpp
#include "header.h"
现在正在编译p1.cpp
和p2.cpp
没问题,没有更多符号重复错误。
答案 1 :(得分:1)
不要将所有头文件的内容复制到一个巨型头文件中,而应考虑使用#include
语句。
mylibrary.h:
#include "myfile1.h"
#include "myfile2.h"
#include "myfile3.h"