显式模板特化 - 多重定义
Explicit template specialization - multiple definitions
我以前做过明确的专业化,我就是不明白为什么这不起作用:
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"
。
我该如何尝试修复此错误? class StringUtils
有什么问题吗?
函数模板的显式(完全)特化遵循单一定义规则,因此 StringUtils::toString<std::string>
不得在多个翻译单元中定义。您可以通过声明 inline
.
来解决这个问题
除了中提供的解决方案外,您还可以在.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
模板函数专业化几乎总是错误的答案。
类 是糟糕的命名空间。
简单地重载而不是专门化。
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 扩展。只需在 X
的命名空间中重载 to_steing(X)
,StringUtils::toString(X)
就能找到它。
您的直接问题是您需要标记专业化 inline
。
我以前做过明确的专业化,我就是不明白为什么这不起作用:
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"
。
我该如何尝试修复此错误? class StringUtils
有什么问题吗?
函数模板的显式(完全)特化遵循单一定义规则,因此 StringUtils::toString<std::string>
不得在多个翻译单元中定义。您可以通过声明 inline
.
除了
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
模板函数专业化几乎总是错误的答案。
类 是糟糕的命名空间。
简单地重载而不是专门化。
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 扩展。只需在 X
的命名空间中重载 to_steing(X)
,StringUtils::toString(X)
就能找到它。
您的直接问题是您需要标记专业化 inline
。