16

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?

laurent
  • 88,262
  • 77
  • 290
  • 428
  • Possible duplicate of [error LNK2005: already defined - C++](https://stackoverflow.com/questions/622229/error-lnk2005-already-defined-c) – JaMiT Jul 06 '19 at 16:32

3 Answers3

35

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:

  1. Declare the functions as static, which implies internal linkage
  2. Inline the functions
  3. 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.

Community
  • 1
  • 1
pepsi
  • 6,785
  • 6
  • 42
  • 74
  • 2
    You are correct. This is why you should avoid implementing functions inside of headers. – Chris Eberle Aug 06 '11 at 05:25
  • `inline` does _not_ imply interal linkage. http://stackoverflow.com/questions/4957582/how-can-i-prove-that-inline-functions-default-to-internal-linkage – CB Bailey Aug 06 '11 at 08:15
7

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

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • That worked, thanks. I'm curious though - why does the compiler include the file twice even though there is an include guard? – laurent Aug 06 '11 at 04:51
  • 1
    It's a separate translation unit - macro defines do not span translation units (compiler invocations). The linker now has 2 definitions of round, and errors out. `static` is also correct for solving the issue. – Yann Ramin Aug 06 '11 at 05:18
1

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

David Stone
  • 26,872
  • 14
  • 68
  • 84