我还在学习如何使用可变参数模板。基本上我想要做的是使用包含STLContainer
类型元素的String
。 STL容器不接受固定数量的参数,因此我尝试使用可变参数模板。如果我理解正确,我应该写下这个:
/* Take a container of String and return a string of those elements separated by commas.*/
template < template <typename String, typename ... Traits > class STLContainer >
String as_comma_list(const STLContainer<String, Traits> &container)
{
String result;
for (auto it = container.begin(); it != container.end(); it++)
{
result += *it;
result += ",";
}
result.pop_back(); // pop last comma
return result;
}
然而编译器(Apple LLVM version 8.1.0
)吐出:
error: use of undeclared identifier 'Traits'
非常感谢任何帮助。
编辑:我最终选择了@ Pixelchemist的回答,因为它似乎是最通用的证明&#34;解决方案,并提供我的代码洞察力。但是,我想说@ Walter的回答是等同的。虽然@ max66的答案是最简单的解决问题,但最初的问题是我试图错误地描述一个STL容器。
答案 0 :(得分:1)
怎么样?
template <template <typename...> class STLContainer,
typename String, typename Traits>
String as_comma_list(const STLContainer<String, Traits> &container)
但你需要Traits
?
我想您可以按照以下方式简化代码
template <template <typename...> class STLContainer, typename String>
String as_comma_list(const STLContainer<String> &container)
答案 1 :(得分:1)
尝试以这种方式编写通用代码肯定会失败,因为通常容器不能被描述为container<T, traits...>
,请考虑map<key, T, Compare, Allocator>
,其中value_type=pair<key, T>
。
相反,在C ++中,这种类型的泛型编程通常是通过iterators
完成的(就像整个标准库一样),例如。
template<typename It>
enable_if_t<is_same<string, typename iterator_traits<It>::value_type>::value,
string> // or use static_assert() in the function body
as_comma_list(It begin, const It &end)
{
string result;
for(; begin!=end; ++begin)
{
result += *begin;
result += ",";
}
result.pop_back();
return result;
}
答案 2 :(得分:0)
template < template <class...> class STLContainer, class String, class ...Traits>
String as_comma_list(const STLContainer<String, Traits...> &container)
类型STLContainer
必须采用模板参数。如果我写了一个类simplestringvector
(我知道这不是通用的,但没有人不能阻止我:))你的代码对我不起作用。
STLContainer
类型必须提供begin()
和end()
成员。 (没有免费功能;没有std::begin
和std::end
)
String
类型必须提供pop_back()
成员。
String
类型必须定义operator+=
,且必须能够处理包含char
的字符串文字(无wchar_t
,无{{1} },...)。
其他不太重要的问题。
没有保证因为我很累但是无论如何......
如果您的代码要求类型可以迭代,那么您首先不需要知道String的类型。您可以将其作为解除引用容器迭代器的衰减结果。通过将char16_t
和std::begin
拖入范围,您可以启用ADL免费开始和结束函数,同时仍然通过std函数捕获成员函数。
首先是一些标题和辅助类:
std::end
现在我们尝试使用启用ADL的迭代实现#include <type_traits>
#include <iterator>
namespace detail
{
template<class ...> struct comma;
template<> struct comma<char>
{ static constexpr char c = ','; };
template<> struct comma<wchar_t>
{ static constexpr wchar_t c = L','; };
template<> struct comma<char16_t>
{ static constexpr char16_t c = u','; };
template<> struct comma<char32_t>
{ static constexpr char16_t c = U','; };
}
,并且对容器或字符串的模板布局没有任何限制。
as_comma_list
注意:此示例要求String类型也是可迭代的(这是非常常见的),并且它在循环中有第二个分支,在这里处理数十亿个字符串时可能会更慢。