尝试围绕 std::getline 编写包装函数时出现 C++ 链接器错误

C++ Linker error when trying to write wrapper function around std::getline

提问人:FreelanceConsultant 提问时间:7/27/2022 最后编辑:Nicol BolasFreelanceConsultant 更新时间:7/27/2022 访问量:92

问:

我已经从我正在从事的项目中剥离了所有内容,以试图找出导致链接器错误的原因。我正在尝试编写一个包装函数来自定义其行为。std::getline

以下编译,但失败并显示此链接器错误:

.../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

以下是 MWE 代码:

// 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;
    }

}

这让我完全困惑,因为该函数编译和链接正常。这向我表明问题与正在使用的模板有关,而不是与函数所在的命名空间有关。EraseCRLF

C++ 模板 C++17 链接器错误

评论

0赞 Egor 7/27/2022
请看“为什么模板只能在头文件中实现?这个问题的答案也适用于您的情况。
0赞 FreelanceConsultant 7/27/2022
@Egor我完全忘记了这条规则。我对此有疑问。必须将源文件中的函数与头文件中的函数分开实现,以避免出现多个定义链接器错误。我才刚刚想到,但关于模板的规则似乎与此完全相反。那么,为什么将函数实现放在模板函数的头文件中是可以的,而对于非模板函数,这是不行的。
0赞 FreelanceConsultant 7/27/2022
我在这里找到了答案:stackoverflow.com/questions/44335046/......

答: 暂无答案