Function already defined error in C++
I have a file called "SimpleFunctions.h" defined as follow:
#ifndef SIMPLEFUNCTIONS_H
#define SIMPLEFUNCTIONS_H
namespace my_namespace {
double round(double r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); }
float round(float r) { return round((double)r); }
}
#endif // SIMPLEFUNCTIONS_H
This file was previously included in only one file and it was working fine.
开发者_开发百科Now today I have included it in a second file and it no longer works. At link time, it tells me that the function is already defined in "firstfile.obj".
However, since I am using include guards, I would expect the functions to be defined only once, or am I missing something?
By default, these functions have external linkage. That means each translation unit has functions called double round(double r) and float round(float r), which causes a name collision at link time.
Some possible solutions are:
- Declare the functions as static, which implies internal linkage
- Inline the functions
- Move the implementation out of the header and into a c/c++ file
Read more here: What is external linkage and internal linkage?
By the way, include guards protect a single translation unit from including a header file multiple times. That's a different issue that what you're seeing here.
use 'inline'
inline double round(double r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); }
inline float round(float r) { return round((double)r); }
The compiler won't necessarily inline the code (although for this short func it may) but the linker doesn't treat is as a separate function anymore.
Note - include guards stop the same include file being included more than once in the same source file (strictly speaking 'compilation unit') it doesn't stop it being included in separate source files that are linked together. That's why you normally declare it in a header but define the function in a c file
A better way to solve the problem is through templates. Your code will compile fine if you were to do something along the lines of:
template <class T>
T round (T r) {
return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
}
Your linker will stop complaining and you'll have a single function for all of your needs.
This solution can be improved with type traits. See boost::is_floating_point and boost::enable_if
精彩评论