0

I have stripped everything out of a project I was working on to try and figure out what is causing a linker error. I am trying to write a wrapper function around std::getline to customize its behaviour.

The following compiles, but fails with this linker error:

.../bin/ld: CMakeFiles/a.out.dir/main.cpp.o: in function `main':
main.cpp:(.text+0x8b): undefined reference to `std::basic_istream<char, std::char_traits<char> >& myfunctions::GetLine<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
collect2: error: ld returned 1 exit status
make[2]: *** [a.out] Error 1
make[1]: *** [CMakeFiles/a.out.dir/all] Error 2
make: *** [all] Error 2

Here's the MWE code:

// main.cpp

#include "mygetline.h"
#include <iostream>
#include <fstream>

int main(int argc, char* argv[])
{

    const std::string filename("trialbalance.csv");
    std::string line;
    std::ifstream ifs(filename);

    myfunctions::EraseCRLF(line); // seems to be fine

    myfunctions::GetLine(ifs, line); // definitely not fine

    return 0;
}
// mygetline.h

#ifndef MYGETLINE_H
#define MYGETLINE_H


#include <iostream>
#include <string>


namespace myfunctions
{

    void EraseCRLF(std::string &s);

    template<class CharT, class Traits, class Allocator>
    std::basic_istream<CharT, Traits>& GetLine(
        std::basic_istream<CharT,Traits>& input,
        std::basic_string<CharT,Traits,Allocator>& str);

}

#endif // MYGETLINE_H
// mygetline.cpp

#include "mygetline.h"


#include <iostream>
#include <string>
#include <algorithm>


namespace myfunctions
{

    void EraseCRLF(std::string &s)
    {
        s.erase(std::remove(s.begin(), s.end(), '\r' ), s.end());
        s.erase(std::remove(s.begin(), s.end(), '\n' ), s.end());
    }


    template<class CharT, class Traits, class Allocator>
    std::basic_istream<CharT, Traits>& GetLine(
        std::basic_istream<CharT,Traits>& input,
        std::basic_string<CharT,Traits,Allocator>& str)
    {
        auto& ret = std::getline(input, str);
        myfunctions::EraseCRLF(str);
        return ret;
    }

}

This one has me completely baffled because the EraseCRLF function compiles and links ok. This suggests to me the problem is associated with the templates which are being used rather than the namespace the function is in.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • Please take a look at ["Why can templates only be implemented in the header file?"](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file). The answer in this question is also applicable for your case. – Egor Jul 27 '22 at 11:08
  • @Egor I had completely forgotten about this rule. I have a question about this. One has to implement functions in the source file separately from the header file to avoid multiple definition linker errors. It has only just occurred to me but the rule about templates seems to be the exact opposite of this. So why is putting the function implementation in the header file for a template function ok, whereas for a non-template function this is a no-no. – FreelanceConsultant Jul 27 '22 at 13:04
  • I found an answer for that here: https://stackoverflow.com/questions/44335046/how-does-the-linker-handle-identical-template-instantiations-across-translation – FreelanceConsultant Jul 27 '22 at 13:26

0 Answers0