I've made a few new classes for help in reading CSV files in a C++ program, based on code suggested in another stackoverflow post here. Here is the file declaring and defining the classes, along with some helper functions defined outside the classes to convert to different data types:
/**
@file CSVHandler.h
@brief Declaration of a class for handling CSV file reading and writing.
*/
#ifndef SRC_THAMESLIB_CSVHANDLER_H_
#define SRC_THAMESLIB_CSVHANDLER_H_
#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
/**
@class Declare the CSVRow class
This class was taken from an answer at stackoverflow.com:
https://stackoverflow.com/questions/1120140/how-can-i-read-and-parse-csv-files-in-c
*/
class CSVRow {
public:
std::string_view operator[](std::size_t index) const {
return std::string_view(&m_line[m_data[index] + 1],
m_data[index + 1] - (m_data[index] + 1));
}
std::size_t size() const { return m_data.size() - 1; }
void readNextRow(std::istream &str) {
std::getline(str, m_line);
m_data.clear();
m_data.emplace_back(-1);
std::string::size_type pos = 0;
while ((pos = m_line.find(',', pos)) != std::string::npos) {
m_data.emplace_back(pos);
++pos;
}
// This checks for a trailing comma with no data after it.
pos = m_line.size();
m_data.emplace_back(pos);
}
private:
std::string m_line;
std::vector<int> m_data;
};
std::istream &operator>>(std::istream &str, CSVRow &data) {
data.readNextRow(str);
return str;
}
/**
@class Declare the CSVIterator class
This class was taken from an answer at stackoverflow.com:
https://stackoverflow.com/questions/1120140/how-can-i-read-and-parse-csv-files-in-c
*/
class CSVIterator {
public:
typedef std::input_iterator_tag iterator_category;
typedef CSVRow value_type;
typedef std::size_t difference_type;
typedef CSVRow *pointer;
typedef CSVRow &reference;
CSVIterator(std::istream &str) : m_str(str.good() ? &str : nullptr) {
++(*this);
}
CSVIterator() : m_str(nullptr) {}
// Pre Increment
CSVIterator &operator++() {
if (m_str) {
if (!((*m_str) >> m_row)) {
m_str = nullptr;
}
}
return *this;
}
// Post increment
CSVIterator operator++(int) {
CSVIterator tmp(*this);
++(*this);
return tmp;
}
CSVRow const &operator*() const { return m_row; }
CSVRow const *operator->() const { return &m_row; }
bool operator==(CSVIterator const &rhs) {
return ((this == &rhs) ||
((this->m_str == nullptr) && (rhs.m_str == nullptr)));
}
bool operator!=(CSVIterator const &rhs) { return !((*this) == rhs); }
private:
std::istream *m_str;
CSVRow m_row;
};
/**
@class Declare the CSVRange class
This class was taken from an answer at stackoverflow.com:
https://stackoverflow.com/questions/1120140/how-can-i-read-and-parse-csv-files-in-c
*/
class CSVRange {
std::istream &stream;
public:
CSVRange(std::istream &str) : stream(str) {}
CSVIterator begin() const { return CSVIterator{stream}; }
CSVIterator end() const { return CSVIterator{}; }
};
// Handler functions to convert to different data types
int row2int(const std::string_view &string) {
int result = std::stoi(std::string(string));
return (result);
}
double row2double(const std::string_view &string) {
double result = std::stod(std::string(string));
return (result);
}
#endif // SRC_THAMESLIB_CSVHANDLER_H_
The problem is that when I now compile the library I get a linking error saying that these helper functions and the overloaded >> operator are duplicates:
[ 73%] Built target thameslib
[ 78%] Linking CXX executable thames
duplicate symbol 'row2int(std::__1::basic_string_view<char, std::__1::char_traits<char>> const&)' in:
/Users/jwbullard/Software/THAMES/build/CMakeFiles/thames.dir/src/thames.cc.o
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[11](Lattice.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[9](KineticController.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[4](Controller.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[15](StandardKineticModel.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[13](PozzolanicModel.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[12](ParrotKillohModel.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[10](KineticModel.cc.o)
duplicate symbol 'row2double(std::__1::basic_string_view<char, std::__1::char_traits<char>> const&)' in:
/Users/jwbullard/Software/THAMES/build/CMakeFiles/thames.dir/src/thames.cc.o
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[11](Lattice.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[9](KineticController.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[4](Controller.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[15](StandardKineticModel.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[13](PozzolanicModel.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[12](ParrotKillohModel.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[10](KineticModel.cc.o)
duplicate symbol 'operator>>(std::__1::basic_istream<char, std::__1::char_traits<char>>&, CSVRow&)' in:
/Users/jwbullard/Software/THAMES/build/CMakeFiles/thames.dir/src/thames.cc.o
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[11](Lattice.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[9](KineticController.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[4](Controller.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[15](StandardKineticModel.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[13](PozzolanicModel.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[12](ParrotKillohModel.cc.o)
/Users/jwbullard/Software/THAMES/build/src/thameslib/libthameslib.a[10](KineticModel.cc.o)
ld: 3 duplicate symbols
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [thames] Error 1
I thought that having the header guards would prevent this kind of duplication, but I guess not. Can anyone give me some advice on how to correct this?
inlinekeyword in front of those function definitions in the header.