我相信,最优雅的解决方案是:
#include <string>
template <typename T>
typename std::enable_if<std::is_constructible<std::string, T>::value, std::string>::type
stringify(T&& value) {
return std::string(std::forward<T>(value));
}
template <typename T>
typename std::enable_if<!std::is_constructible<std::string, T>::value, std::string>::type
stringify(T&& value) {
using std::to_string;
return to_string(std::forward<T>(value));
}
在这里,如果我们可以使用
T
构造
std::string
(我们通过
std::is_constructible<std::string, T>
进行检查),那么我们就这样做,否则我们使用
to_string
。
当然,在C++14中,你可以用更短的
std::enable_if_t<...>
代替
typename std::enable_if<...>::type
。下面是代码的较短版本示例。
下面是一个较短的版本,但它的效率稍微低一些,因为它需要对
std::string
进行额外的移动(但如果我们只做一个复制,效率会更低)。
#include <string>
std::string stringify(std::string s) {
return std::move(s);
}
template <typename T>
std::enable_if_t<!std::is_convertible<T, std::string>::value, std::string>
stringify(T&& value) {
using std::to_string;
return to_string(std::forward<T>(value));
}
此版本在可能的情况下使用隐式转换为std::string
,否则使用to_string
。请注意使用std::move
来利用C++11的移动语义。
这就是为什么我的解决方案比当前最受欢迎的解决方案更好,由@cerkiewny提供:
它具有更广泛的适用性,因为通过ADL,它也适用于任何定义了使用函数to_string
进行转换的类型(不仅限于std::
版本),请参见下面的示例用法。而@cerkiewny的解决方案仅适用于基本类型和可以构造为std::string的类型。
当然,在他的情况下,可以添加其他类型的额外重载stringify
,但如果与添加新的ADL版本的to_string
相比,则这是一个不太可靠的解决方案。而且很有可能,ADL兼容的to_string
已经在第三方库中为我们要使用的类型定义了。在这种情况下,使用我的代码,您根本不需要编写任何其他代码即可使stringify
正常工作。
它更有效率,因为它利用C++11的完美转发(通过使用通用引用(T&&
)和std::forward
)。
示例用法:
#include <string>
namespace Geom {
class Point {
public:
Point(int x, int y) : x(x), y(y) {}
friend std::string to_string(const Point& p) {
return '(' + std::to_string(p.x) + ", " + std::to_string(p.y) + ')';
}
private:
int x;
int y;
};
}
#include <iostream>
#include "stringify.h"
int main() {
double d = 1.2;
std::cout << stringify(d) << std::endl;
char s[] = "Hello, World!";
std::cout << stringify(s) << std::endl;
Geom::Point p(1, 2);
std::cout << stringify(p) << std::endl;
}
备选方案,但不推荐使用
我也考虑过仅仅重载 to_string
:
template <typename T>
typename std::enable_if<std::is_constructible<std::string, T>::value, std::string>::type
to_string(T&& value) {
return std::string(std::forward<T>(value));
}
还可以使用隐式转换为std::string
的简短版本:
std::string to_string(std::string s) {
return std::move(s);
}
但是这种方法有严重的局限性:我们需要记住在每个想要使用它的地方写
to_string
而不是
std::to_string
;并且它与最常见的
ADL使用模式不兼容。
int main() {
std::string a = std::to_string("Hello World!");
using std::to_string;
std::string b = to_string("Hello World!");
}
很可能,这种方法还存在其他问题。
在与此方法相关的其他问题上。
std::stringstream
依赖?因为在std::to_string
出现之前,我就用过SSTR()宏,一直很喜欢它的多个<<
链接的能力,但不能真正将其作为答案发布,因为你说“不使用stringstream”... - DevSolar