Bar*_*yne 4 c++ templates type-traits c++11
我正在处理一些遗留代码,这些代码在头文件中定义了以下模板:
template<typename T>
std::string convertToString(const T& t);
Run Code Online (Sandbox Code Playgroud)
在同一个头文件中,有一些用户定义类型的专门化。在 .cpp 文件中,有 types 的专门化int,unsigned short如下unsigned long所示:
template<>
std::string convertToString<unsigned short>(const unsigned short& s) {
... some implementation ...
}
template<>
std::string convertToString<int>(const int & s) {
... some implementation ...
}
template<>
std::string convertToString<unsigned long>(const unsigned long& value) {
... some implementation ...
}
Run Code Online (Sandbox Code Playgroud)
这些实现不使用 C++11 的std::to_string函数。我想简化这段代码,以便对于所有std::to_string支持的类型,即
int
long
long long
unsigned
unsigned long
unsigned long long
float
double
long double
Run Code Online (Sandbox Code Playgroud)
模板专门化使用简单的实现(例如 int):
template<>
std::string convertToString(const int& n) { return std::to_string(n); }
Run Code Online (Sandbox Code Playgroud)
我当然可以写下所有上述类型的所有模板专业化,但这似乎不是一个好方法。我当前为所有类型提供这些模板专业化的最佳解决方案std::to_string是将以下内容添加到我的头文件中:
template<typename T>
std::string convertToString(const T& t);
template <typename T,
typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
std::string convertToString(const T& t)
{
return std::to_string(t);
}
Run Code Online (Sandbox Code Playgroud)
我认为这已经接近解决方案,但还没有,因为我收到以下歧义错误:
error: call of overloaded 'convertToString(long unsigned int&)' is ambiguous
Run Code Online (Sandbox Code Playgroud)
我将上述两个模板函数作为可能的候选函数。我不太明白为什么如果第二个存在的话第一个也是可能的候选者......
如何为所有std::to_string支持的类型添加模板专业化,并且仍然允许在convertToString函数模板中使用用户定义的类型 T?目前解决方案应仅限于 C++11...
更新:在下面添加一个最小的工作示例(代码必须是 C++11):
所以我想用更简单的代码替换以下代码:
#include <iostream>
#include <string>
struct A {};
template<typename T>
std::string convertToString(const T& t);
template<>
std::string convertToString(const int& n) { return std::to_string(n); }
template<>
std::string convertToString(const long& n) { return std::to_string(n); }
template<>
std::string convertToString(const long long& n) { return std::to_string(n); }
template<>
std::string convertToString(const unsigned& n) { return std::to_string(n); }
template<>
std::string convertToString(const unsigned long& n) { return std::to_string(n); }
template<>
std::string convertToString(const unsigned long long& n) { return std::to_string(n); }
template<>
std::string convertToString(const float& n) { return std::to_string(n); }
template<>
std::string convertToString(const double& n) { return std::to_string(n); }
template<>
std::string convertToString(const long double& n) { return std::to_string(n); }
template<>
std::string convertToString<A>(const A& a) { return std::string("foo"); }
int main()
{
std::cout << convertToString(1) << std::endl;
std::cout << convertToString(2L) << std::endl;
std::cout << convertToString(3LL) << std::endl;
std::cout << convertToString(4U) << std::endl;
std::cout << convertToString(5UL) << std::endl;
std::cout << convertToString(6ULL) << std::endl;
std::cout << convertToString(7.0f) << std::endl;
std::cout << convertToString(8.0) << std::endl;
std::cout << convertToString(9.0L) << std::endl;
std::cout << convertToString(A()) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我尝试了以下方法,这给了我编译器错误:
#include <iostream>
#include <string>
#include <type_traits>
struct A {};
template<typename T,
typename = typename std::enable_if<!std::is_arithmetic<T>::value>::type>
std::string convertToString(const T& t);
template <typename T,
typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
std::string convertToString(const T& t)
{
return std::to_string(t);
}
template<>
std::string convertToString<A>(const A& a) { return std::string("foo"); }
int main()
{
std::cout << convertToString(A()) << std::endl;
std::cout << convertToString(1) << std::endl;
std::cout << convertToString(2L) << std::endl;
std::cout << convertToString(3LL) << std::endl;
std::cout << convertToString(4U) << std::endl;
std::cout << convertToString(5UL) << std::endl;
std::cout << convertToString(6ULL) << std::endl;
std::cout << convertToString(7.0f) << std::endl;
std::cout << convertToString(8.0) << std::endl;
std::cout << convertToString(9.0L) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
如果有人可以向我解释这有什么问题,那就太好了。
您可以创建一个类型特征来检查是否std::to_string(t)有效,并使用 SFINAE 仅允许std::to_string在有效时实例化的重载。
类型特征示例:
#include <type_traits>
#if __cplusplus >= 201703L
using std::void_t;
#else
template <class...>
using void_t = void; // borrowed from C++17
#endif
template <class T, class = void>
struct has_to_string : std::false_type {};
template <class T>
struct has_to_string<T, void_t<decltype(std::to_string(std::declval<T>()))>>
: std::true_type {};
Run Code Online (Sandbox Code Playgroud)
使用示例:
template <class T>
typename std::enable_if<has_to_string<T>::value, std::string>::type
convertToString(const T& t) {
return std::to_string(t);
}
Run Code Online (Sandbox Code Playgroud)
您可以为 SFINAE 编写两个具有分离条件的重载:
// overload for T is not is_arithmetic
template<typename T>
typename std::enable_if<!std::is_arithmetic<T>::value,std::string>::type convertToString(const T& t);
// overload for T is arithmetic
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value,std::string>::type convertToString(const T& t)
{
return std::to_string(t);
}
Run Code Online (Sandbox Code Playgroud)