0

我以前做过明确的专业化,我只是不明白为什么这不起作用:

StringUtils.hpp

#ifndef AYC_STRINGUTILS_HPP
#define AYC_STRINGUTILS_HPP

#include <string>

class StringUtils {
public:
    template <typename T>
    static std::string toString(const T& t);
};

#include "StringUtils.tpp"

#endif //AYC_STRINGUTILS_HPP

StringUtils.tpp

#include "StringUtils.hpp"

template<typename T>
std::string StringUtils::toString(const T& t) {
    return std::to_string(t);
}

template<>
std::string StringUtils::toString<std::string>(const std::string& t) {
    return t;
}

我得到的错误是抱怨函数的多个定义的链接器错误toString

项目中的许多文件使用#include "StringUtils.hpp".

如何尝试修复此错误?课堂上有什么问题StringUtils吗?

4

3 回答 3

2

函数模板的显式(完整)特化受单定义规则的约束,因此StringUtils::toString<std::string>不得在多个翻译单元中定义。你可以通过声明它来解决这个问题inline

于 2018-12-06T22:29:38.083 回答
2

除了Brian 在答案中提供的解决方案之外,您还可以在 .hpp/.tpp 文件中声明专业化并在 .cpp 文件中定义它。

StringUtils.hpp 文件:

#ifndef AYC_STRINGUTILS_HPP
#define AYC_STRINGUTILS_HPP

#include <string>

class StringUtils {
public:
    template <typename T>
    static std::string toString(const T& t);
};

// Generic implementation.
template<typename T>
std::string StringUtils::toString(const T& t) {
    return std::to_string(t);
}

// Declation of the specialization.
template<>
std::string StringUtils::toString<std::string>(const std::string& t);

#endif //AYC_STRINGUTILS_HPP

StringUtils.cpp 文件:

#include "StringUtils.hpp"

// Definition of the specialization.
template<>
std::string StringUtils::toString<std::string>(const std::string& t) {
    return t;
}

测试程序:

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

int main()
{
   std::string a("test");
   std::cout << StringUtils::toString(a) << std::endl;
   std::cout << StringUtils::toString(10) << std::endl;
}

测试程序的输出:

test
10
于 2018-12-06T22:42:42.967 回答
0

模板函数专业化几乎总是错误的答案。

类是糟糕的命名空间。

简单地重载而不是专门化。

namespace StringUtils {
  template <typename T>
  std::string toString(const T& t){
    using std::to_string;
    return to_string(t);
  }
  inline std::string toString(std::string s){ return std::move(s); }
}

重载解析可以满足您的要求,并且它允许有效的签名变化(如上面,我采用s按值,这可以避免额外的堆分配)。

to_string另请注意,我为自定义类启用了 ADL 扩展。只需to_steing(X)X's 命名空间中重载并StringUtils::toString(X)找到它。


您当前的问题是您需要标记专业化inline

于 2018-12-06T23:41:48.880 回答