Container::value_type 的模板专业化
Template specialization by Container::value_type
我使用以下两个函数将 std 容器转换为字符串以进行日志记录。
template <typename TCollection, std::string(*ToStringFunc)(typename TCollection::value_type)>
std::string LOG_COLLECTION(const TCollection& collection)
{
std::string as_str;
for (const auto& element : collection)
{
as_str += ToStringFunc(element) + " ";
}
return as_str;
}
template <typename TCollection>
std::string LOG_COLLECTION(const TCollection& collection)
{
return LOG_COLLECTION<TCollection, std::to_string>(collection);
}
我想要 std::string
容器的专业化。类似于以下内容:
template <typename TCollection<std::string>>
std::string LOG_COLLECTION(const TCollection<std::string>& collection)
{
std::string as_str;
for (const auto& element : collection)
{
as_str += ToStringFunc(element) + " ";
}
return as_str;
}
int main()
{
std::vector<std::string> vec{ "a", "b", "c" };
std::string as_str = LOG_COLLECTION(vec)
}
我该怎么做(我正在使用 c++11
)?我试图在网上搜索但没有找到解决方案。
#include <string>
#include <vector>
template <typename TCollection, std::string (*ToStringFunc)(typename TCollection::value_type)>
std::string LOG_COLLECTION(const TCollection& collection) {
std::string as_str;
for (const auto& element : collection) {
as_str += ToStringFunc(element) + " ";
}
return as_str;
}
template<class T>
std::string my_to_string(T val) {
return std::to_string(val);
}
template<>
std::string my_to_string(std::string val) {
return val;
}
template <typename TCollection>
std::string LOG_COLLECTION(const TCollection& collection) {
return LOG_COLLECTION<TCollection, &my_to_string<typename TCollection::value_type>>(collection);
}
int main() {
auto v = std::vector<int>{1, 2, 3};
LOG_COLLECTION(v);
auto v2 = std::vector<std::string>{"A", "aaa", "ee"};
LOG_COLLECTION(v);
}
解决方案-一:使用template template arguments
点赞 @Scheff suggested in the comments, you can provide a template template function specialization std::string
秒。
以下是示例代码:(See Online Live)
#include <iostream>
#include <vector>
#include <string>
// template alias for function pointer
template<template<class...> class TCollection, typename ValueType>
using FunctionPtrType = std::string(*)(typename TCollection<ValueType>::value_type);
// `LOG_COLLECTION` for the Container<non-std::string>
template <template<class...> class TCollection, typename ValueType>
std::string LOG_COLLECTION(const TCollection<ValueType>& collection,
FunctionPtrType<TCollection, ValueType> ToStringFunc)
{
std::string as_str;
for (const ValueType element : collection) {
as_str += ToStringFunc(element) + " ";
}
return as_str;
}
// `LOG_COLLECTION` for the Container<std::string>
template <template<class...> class TCollection, typename... Args>
std::string LOG_COLLECTION(const TCollection<std::string, Args...>& collection)
{
std::string as_str;
for (const auto& element : collection) {
as_str += (element + " ");
}
return as_str;
}
int main()
{
std::vector<int> vec{ 1, 2, 3 };
// call the Container<non-std::string> like
std::string as_str = LOG_COLLECTION(vec,
[](int val) { return ::std::to_string(val); });
std::vector<std::string> vec2{ "1", "2", "3" };
std::string as_str2 = LOG_COLLECTION(vec2); // call with no `ToString` function!
}
解决方案-二:使用SFINAE
或者 SFINAE(“替换失败不是错误”)LOG_COLLECTION
函数如下:
#include <type_traits> // std::integral_constant, std::is_same, std::enable_if
// traits for checking the `value_type == std::string`
template<class Container> struct has_std_string_value_type final
: public std::integral_constant<bool, std::is_same<std::string, typename Container::value_type>::value>
{};
// template alias for function pointer
template<typename TCollection>
using FunctionPtrType = std::string(*)(typename TCollection::value_type);
// for the Container<non-std::string>
template <typename TCollection>
auto LOG_COLLECTION(const TCollection& collection, FunctionPtrType<TCollection> ToStringFunc)
-> typename std::enable_if<! has_std_string_value_type<TCollection>::value, std::string>::type
{
std::string as_str;
for (const auto element : collection) {
as_str += ToStringFunc(element) + " ";
}
return as_str;
}
// for the Container<std::string>
template <typename TCollection>
auto LOG_COLLECTION(const TCollection& collection)
-> typename std::enable_if<has_std_string_value_type<TCollection>::value, std::string>::type
{
std::string as_str;
for (const auto& element : collection) {
as_str += (element + " ");
}
return as_str;
}
我使用以下两个函数将 std 容器转换为字符串以进行日志记录。
template <typename TCollection, std::string(*ToStringFunc)(typename TCollection::value_type)>
std::string LOG_COLLECTION(const TCollection& collection)
{
std::string as_str;
for (const auto& element : collection)
{
as_str += ToStringFunc(element) + " ";
}
return as_str;
}
template <typename TCollection>
std::string LOG_COLLECTION(const TCollection& collection)
{
return LOG_COLLECTION<TCollection, std::to_string>(collection);
}
我想要 std::string
容器的专业化。类似于以下内容:
template <typename TCollection<std::string>>
std::string LOG_COLLECTION(const TCollection<std::string>& collection)
{
std::string as_str;
for (const auto& element : collection)
{
as_str += ToStringFunc(element) + " ";
}
return as_str;
}
int main()
{
std::vector<std::string> vec{ "a", "b", "c" };
std::string as_str = LOG_COLLECTION(vec)
}
我该怎么做(我正在使用 c++11
)?我试图在网上搜索但没有找到解决方案。
#include <string>
#include <vector>
template <typename TCollection, std::string (*ToStringFunc)(typename TCollection::value_type)>
std::string LOG_COLLECTION(const TCollection& collection) {
std::string as_str;
for (const auto& element : collection) {
as_str += ToStringFunc(element) + " ";
}
return as_str;
}
template<class T>
std::string my_to_string(T val) {
return std::to_string(val);
}
template<>
std::string my_to_string(std::string val) {
return val;
}
template <typename TCollection>
std::string LOG_COLLECTION(const TCollection& collection) {
return LOG_COLLECTION<TCollection, &my_to_string<typename TCollection::value_type>>(collection);
}
int main() {
auto v = std::vector<int>{1, 2, 3};
LOG_COLLECTION(v);
auto v2 = std::vector<std::string>{"A", "aaa", "ee"};
LOG_COLLECTION(v);
}
解决方案-一:使用template template arguments
点赞 @Scheff suggested in the comments, you can provide a template template function specialization std::string
秒。
以下是示例代码:(See Online Live)
#include <iostream>
#include <vector>
#include <string>
// template alias for function pointer
template<template<class...> class TCollection, typename ValueType>
using FunctionPtrType = std::string(*)(typename TCollection<ValueType>::value_type);
// `LOG_COLLECTION` for the Container<non-std::string>
template <template<class...> class TCollection, typename ValueType>
std::string LOG_COLLECTION(const TCollection<ValueType>& collection,
FunctionPtrType<TCollection, ValueType> ToStringFunc)
{
std::string as_str;
for (const ValueType element : collection) {
as_str += ToStringFunc(element) + " ";
}
return as_str;
}
// `LOG_COLLECTION` for the Container<std::string>
template <template<class...> class TCollection, typename... Args>
std::string LOG_COLLECTION(const TCollection<std::string, Args...>& collection)
{
std::string as_str;
for (const auto& element : collection) {
as_str += (element + " ");
}
return as_str;
}
int main()
{
std::vector<int> vec{ 1, 2, 3 };
// call the Container<non-std::string> like
std::string as_str = LOG_COLLECTION(vec,
[](int val) { return ::std::to_string(val); });
std::vector<std::string> vec2{ "1", "2", "3" };
std::string as_str2 = LOG_COLLECTION(vec2); // call with no `ToString` function!
}
解决方案-二:使用SFINAE
或者 SFINAE(“替换失败不是错误”)LOG_COLLECTION
函数如下:
#include <type_traits> // std::integral_constant, std::is_same, std::enable_if
// traits for checking the `value_type == std::string`
template<class Container> struct has_std_string_value_type final
: public std::integral_constant<bool, std::is_same<std::string, typename Container::value_type>::value>
{};
// template alias for function pointer
template<typename TCollection>
using FunctionPtrType = std::string(*)(typename TCollection::value_type);
// for the Container<non-std::string>
template <typename TCollection>
auto LOG_COLLECTION(const TCollection& collection, FunctionPtrType<TCollection> ToStringFunc)
-> typename std::enable_if<! has_std_string_value_type<TCollection>::value, std::string>::type
{
std::string as_str;
for (const auto element : collection) {
as_str += ToStringFunc(element) + " ";
}
return as_str;
}
// for the Container<std::string>
template <typename TCollection>
auto LOG_COLLECTION(const TCollection& collection)
-> typename std::enable_if<has_std_string_value_type<TCollection>::value, std::string>::type
{
std::string as_str;
for (const auto& element : collection) {
as_str += (element + " ");
}
return as_str;
}