Search code examples
c++namespacesheader-filesfunction-definition

CodeBlocks Compiler Giving "Undefined Reference" Error Over Usage of a Function Declared in My Header File


I'm getting the following error when trying to build and run my C++ Project:

||=== Build: Debug in CS II (compiler: GNU GCC Compiler) ===|

obj\Debug\main.o||In function 'main':|
|30|undefined reference to '(anonymous namespace)::deleteRepeats(char*)'||

|error: ld returned 1 exit status|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

My code is as follows for each file (I wouldn't be surprised if a lot is buggy or just plain wrong, as I haven't been able to test it at all and my focus has been on remedying that):

main.cpp:

#include <iostream>
#include "implementation.hpp"

int main()
{
    char originalArray[SIZE];
    originalArray[0] = 'a';
    originalArray[1] = 'b';
    originalArray[2] = 'b';
    originalArray[3] = 'c';
    originalArray[4] = 'a';
    originalArray[5] = 'c';
    originalArray[6] = 'a';
    originalArray[7] = 'c';
    originalArray[8] = 'b';
    originalArray[9] = 'c';
    char *noRepeats;
    noRepeats = deleteRepeats(&(originalArray[0]));
    std::cout << noRepeats;
    return 0;

}

implementation.hpp:

#ifndef IMPLEMENTATION_HPP
#define IMPLEMENTATION_HPP
namespace
{
    const int SIZE = 10;
    char* deleteRepeats(char*);
}
#endif

implementation.cpp:

#include "implementation.hpp"

char* deleteRepeats(char* array_to_edit)
{
    char new_array[SIZE];
    int num_of_unique_letters_seen = 0;
    for (int letter = 0; letter < SIZE; letter++)
    {
        bool already_exists = false;
        for (int letter_seen = 0; letter_seen < num_of_unique_letters_seen; letter_seen++)
        {
            if (array_to_edit[letter] == new_array[letter_seen])
            {
                already_exists = true;
            }
        }
        if (!already_exists)
        {
            new_array[num_of_unique_letters_seen] = array_to_edit[letter];
            num_of_unique_letters_seen++;
        }
    }
    return &new_array[0];
}

I was prompted to ask this question in the comments of the answer to this question, which is very similar, but the accepted answer was already completed in my project when the issue arose.

Code where the namespace is given a name:

main.cpp:

#include <iostream>
#include "implementation.hpp"

int main()
{
    char originalArray[dts::SIZE];
    originalArray[0] = 'a';
    originalArray[1] = 'b';
    originalArray[2] = 'b';
    originalArray[3] = 'c';
    originalArray[4] = 'a';
    originalArray[5] = 'c';
    originalArray[6] = 'a';
    originalArray[7] = 'c';
    originalArray[8] = 'b';
    originalArray[9] = 'c';
    char *noRepeats;
    noRepeats = dts::deleteRepeats(&(originalArray[0]));
    std::cout << noRepeats;
    return 0;

}

implementation.cpp:

#include "implementation.hpp"

char* deleteRepeats(char* array_to_edit)
{
    char new_array[dts::SIZE];
    int num_of_unique_letters_seen = 0;
    for (int letter = 0; letter < dts::SIZE; letter++)
    {
        bool already_exists = false;
        for (int letter_seen = 0; letter_seen < num_of_unique_letters_seen; letter_seen++)
        {
            if (array_to_edit[letter] == new_array[letter_seen])
            {
                already_exists = true;
            }
        }
        if (!already_exists)
        {
            new_array[num_of_unique_letters_seen] = array_to_edit[letter];
            num_of_unique_letters_seen++;
        }
    }
    for (int letter = 0; letter < dts::SIZE; letter++)
    {
        array_to_edit[letter] = new_array[letter];
    }
    return array_to_edit;
}

implementation.hpp:

#ifndef IMPLEMENTATION_HPP
#define IMPLEMENTATION_HPP
namespace dts
{
    const int SIZE = 10;
    char* deleteRepeats(char*);
}
#endif

Solution

  • The idea of a namespace is to resolve conflicts if e.g. functions happen to have the same name. Kind of like surnames for people, to tell John Bakerson and John Miller apart from each other.

    So one John lives in the namespace Bakerson and the other in namespace Miller.

    If you use namespaces, always tell the compiler which namespace your function belongs to.

    // .hpp

    namespace Bakerson {
      void John();
    }
    
    namespace Miller {
      void John();
    }
    

    // .cpp

    namespace Bakerson {
      void John(){
        std::cout << "I'm John Bakerson.\n";
      }
    }
    
    namespace Miller {
      void John(){
        std::cout << "I'm John Miller.\n";
      }
    }