目前,我有一个这样的函数模板,它将vector
转换为string
(只是一个自然字符串,用逗号分隔元素):
//the type T must be passable into std::to_string
template<typename T>
std::string vec_to_str(const std::vector<T> &vec);
如您所见,这仅适用于其元素可以传递到内置std::to_string
函数(例如int
,double
等)的矢量。
在评论中记录允许的T
是否被视为一种良好做法?如果没有,我该怎么办?是否有可能以更好的方式加强这一点?
答案 0 :(得分:4)
使用static_assert
和一些表达式SFINAE,您可以得到一个很好的编译时错误消息:
template<typename T>
constexpr auto allowed(int) -> decltype(std::to_string(std::declval<T>()), bool())
{
return true;
}
template<typename>
constexpr bool allowed(...)
{
return false;
}
template<typename T>
std::string vec_to_str(const std::vector<T>& vec)
{
static_assert(allowed<T>(0), "Invalid value type.");
return "";
}
struct foo {};
int main()
{
std::vector<int> v_int;
vec_to_str(v_int);
std::vector<foo> v_double;
vec_to_str(v_double); // static_assert fires here
}
答案 1 :(得分:2)
由于std::to_string
是C ++ 11的一个特性,我猜你可能对C ++ 11解决方案持开放态度。在这种特殊情况下,您可以以sfinae方式使用尾随返回类型:
template <typename T>
auto vec_to_str(const std::vector<T>& vec) -> decltype(std::to_string(std::declval<T>()));
如果值类型不适用于to_string
,则无法替换(并消除该重载)。但是,这并不一定是记录和执行规则最令人赏心悦目的方式。可能还有上述Sfinae技巧的前C ++ 11版本,但它不会更漂亮。
一般来说,我会说只需在评论中记录它(可能带有doxygen标签,如\tparam
)。您可以使用概念检查机制,采用Boost.Concept样式 - 检查是否需要。
作为旁注,对于这种特定情况,我可能会建议您依赖std::ostream
operator <<
而不是to_string
函数,因为它更有可能是自定义类型(例如,2D矢量或其他东西)将配备过载以输出到流。
答案 2 :(得分:0)
在concepts到达之前,您可以将decltype
与匿名类型参数一起使用:
template<typename T,
typename = decltype(std::to_string(std::declval<T>()))>
std::string vec_to_str(const std::vector<T> &vec);