模板函数多重定义错误

问题描述 投票:0回答:1

有一个巨大的基于 cmake 的、在 Linux 中开发的 C++ 项目。我正在尝试在 Windows 10 中编译它。

当我尝试使用 MSYS2 64 位和 VSCode 构建它时,出现以下

链接错误

[build] [ 98%] Building CXX object CMakeFiles/heca_input_exe.dir/utils/options/structures_from_cmdline.cc.obj [build] [100%] Linking CXX executable heca_input_exe.exe [build] C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles\heca_input_exe.dir/objects.a(string_utils.cc.obj): in function `std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >& utils::split<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, std::vector<char, std::allocator<char> > const&, bool, bool)': [build] C:/Users/pc/Documents/__protein design/___hydrogen bond/BioshellHydrogenBond/utils/string_utils.cc:62: multiple definition of `std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >& utils::split<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, std::vector<char, std::allocator<char> > const&, bool, bool)'; CMakeFiles\heca_input_exe.dir/objects.a(DataTable.cc.obj):C:/Users/pc/DOCUME~1/__protein design/___hydrogen bond/BioshellHydrogenBond/utils/string_utils.hh:140: first defined here

split()

函数声明和定义如下:

//File: string_utils.hh // // ... ... ... ... // /** @brief Splits a string into tokens based on a given delimiter. * * @param str - the input string with tokens to be converted * @param delim - character to be trimmed off (a space by default) * @param if_trim_tokens - if true, tokens will be trimmed of white space characters * @return the newly created vector that holds the tokens extracted from the given string */ std::vector<std::string> split(const std::string &str, const std::vector<char> & delim = {' '}, const bool if_trim_tokens = true,const bool if_trim_line = true); /** @brief Splits a string into a vector of tokens based on a given delimiter. * * @param input_str - input string * @param separator - separator (delimiter) * @param max - maximum number of tokens to be extracted * @param results - vector to insert the resulting tokens */ void split(const std::string &input_str, const std::string &separator, const int max, std::vector<std::string> &results); // // ... ... ... ... // /** @brief Splits a string into tokens based on a given delimiter and converts them into a generic type T * * @tparam T - the final type of the data that will be converted from string * @param s - the input string with tokens to be converted * @param tokens - the resulting (converted) tokens will be stored here * @param delim - character to be trimmed off (a space by default) * @param if_trim_tokens - if true, tokens will be trimmed of white space characters * @return the reference to the vector of converted data */ template<typename T> std::vector<T> & split(const std::string &s, std::vector<T> &tokens, const std::vector<char> & delim = {' '}, const bool if_trim_tokens = true,const bool if_trim_line = true) { std::string s_copy(s); trim(s_copy); // --- replace all delimiters with the first one for(int i=1;i<delim.size();++i) std::replace(s_copy.begin(), s_copy.end(), delim[i], delim[0]); std::stringstream ss(s_copy); std::string item; T data; while (std::getline(ss, item, delim[0])) { if (if_trim_tokens) trim(item); if (item.size() == 0) continue; if(item.find_first_not_of(' ') != std::string::npos) { std::stringstream ss2(item); ss2 >> data; tokens.push_back(data); } } return tokens; } // // ... ... ... //
//File: string_utils.cc
//
// ... ... ... ...
//
void split(const std::string &input_str, const std::string &separator, const int max, std::vector<std::string> &results) {

  std::string str(input_str);
  int i = 0;
  size_t found = str.find_first_of(separator);

  while (found != std::string::npos) {
    if (found > 0) results.push_back(str.substr(0, found));
    str = str.substr(found + 1);
    found = str.find_first_of(separator);
    if (max > -1 && ++i == max) break;
  }

  if (str.length() > 0) results.push_back(str);
}

template<>
std::vector<std::string> &split<std::string>(const std::string &s,
                                             std::vector<std::string> &tokens,
    const std::vector<char> & delim,
    const bool if_trim_tokens,const bool if_trim_line) {

  std::string s_copy(s);

  // --- replace all delimiters with the first one
  for(int i=1;i<delim.size();++i)
    std::replace(s_copy.begin(), s_copy.end(), delim[i], delim[0]);

  if (if_trim_line==true) trim(s_copy);
  std::stringstream ss(s_copy);
  std::string item;
  while (std::getline(ss, item, delim[0])) {
    if (if_trim_tokens) trim(item);
    if (item.size() == 0) continue;
    tokens.push_back(item);
  }

  return tokens;
}
//
// ... ... ... ...
//
我有两个问题:

  1. 如何解决此错误?

  2. 为什么这个错误在 Linux 中不显示?

c++ templates msys2
1个回答
0
投票
如果模板是显式特化的,那么在使用显式特化的特化之前,必须有显式特化的声明。否则该程序是 IFNDR(格式错误,无需诊断)。

由于显式专业化定义仅在您显示的一个

.cc

 翻译单元中可见,因此至少在包括头文件在内的其他翻译单元中将违反这一要求。

您需要在模板定义下方添加显式专业化声明:

template<> std::vector<std::string> &split<std::string>(std::string, std::vector<std::string>, const std::vector<char> &, bool, bool);
它在不同的系统上工作纯属巧合,这是 IFNDR ODR 类型违规导致的常见行为。

© www.soinside.com 2019 - 2024. All rights reserved.