如何简化这些函数模板特化?

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 的专门化intunsigned 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)

如果有人可以向我解释这有什么问题,那就太好了。

Ted*_*gmo 7

您可以创建一个类型特征来检查是否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)


for*_*818 6

您可以为 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)