Reputation: 14313
Sigh, I feel like an idiot. I never had c++ file inclusion properly explained to me until months after I asked his question. Please refrain from commenting on exactly how flawed my setup was, I know perfectly well.
I have a multiple-file project containing many .h and .cpp files. One in particular, io_util.h, produces a bizarre series of errors. For the .h, which contains function declarations but no implementations, compiles perfectly, but in the .cpp, where the function bodies are, every function creates the following error:
Multiple markers at this line
- first defined here
- multiple definition of
`<namespace>::<function name>(<args>)'
The file "io_util.cpp" is included only once in the project, CollectionBase.h. "io_util.h" is only included by "io_util.cpp"
Here are the two files:
.h:
/*
* io_util.h
*/
#ifndef IO_UTIL_H_
#define IO_UTIL_H_
#include <iostream>
#include <sstream>
#include <string>
#include <cmath>
#define IO_DEBUG(a) cout << #a << '=' << a << '\n'
#define CASE_SEP 32
#define NUM_CHAR_SEP 48
namespace std
{
void getVar(int&, int);
void getVar(double&, double);
void getVar(unsigned&, unsigned);
int get_num_digits(int);
int get_digit(int, const int, const int);
string value_of(int);
}
#endif /* IO_UTIL_H_ */
.cpp:
/*
* io_util.cpp
*/
#ifndef IO_H_
#define IO_H_
#include "io_util.h"
namespace std
{
void getVar(int& i, int forbidden = NAN)
{
string str;
while(true)
{
getline(cin,str);
if(str.find_first_not_of("-0123456789") != string::npos || !(stringstream(str) >> i))
{
cout << "invalid input.\n\n";
}
else if(i == forbidden)
{
cout << "illegal value.\n\n";
}
else
{
break;
}
}
}
void getVar(double& d, double forbidden = NAN)
{
string str;
while(true)
{
getline(cin,str);
if(str.find_first_not_of("-.0123456789eE") != string::npos || !(stringstream(str) >> d))
{
cout << "invalid input.\n\n";
}
else if(d == forbidden)
{
cout << "illegal value.\n\n";
}
else
{
break;
}
}
}
void getVar(unsigned & u, unsigned forbidden = NAN)
{
string str;
while(true)
{
getline(cin,str);
if(str.find_first_not_of("0123456789") != string::npos || !(stringstream(str) >> u))
{
cout << "invalid input.\n\n";
}
else if(u == forbidden)
{
cout << "illegal value.\n\n";
}
else
{
break;
}
}
}
int get_num_digits(int i)
{
if(i < 0)
{
i = -i;
}
int result = 1;
while(i > 10)
{
i /= 10;
result++;
}
return result;
}
int get_digit(int i, const int num_digits, const int dig)
{
if(num_digits < dig)
{
return 0;
}
const int dig_p10 = pow(10.0,num_digits - dig);
i -= dig_p10 * round(i/dig_p10);
if (dig < num_digits - 1)
{
i = round(i/int(pow(10.0,num_digits - dig - 1)));
}
return i;
}
string value_of(int i)
{
string str;
if (i < 0)
{
str += "-";
i = -i;
}
const int num_dig = get_num_digits(i);
for(int n = 0; n < num_dig; n++)
{
str += char(get_digit(i, num_dig, n) + NUM_CHAR_SEP);
}
return str;
}
}
#endif /*IO_H_*/
I have looked through many questions on this site regarding similar phenomena but none of them have helped.
Upvotes: 1
Views: 3579
Reputation: 66204
First, io_util.cpp should be in the source file list of code files to be compiled. Everywhere in your project that needs the functionality contained therein should be including io_util.h, including CollectionBase.h. Do not #include .cpp files in anything (i.e. no #include "io_util.cpp" allowed).
Second, your io_util.h header declares functions within the std namespace (which is also a no-no) called getVar(). The default parameter values for the trailing parameters belong there; not in the io_util.cpp file.
Fixing both of those should get you substantially further down the road.
Upvotes: 1