可变参数模板的未声明标识符
Undeclared identifier for Variadic Template
我还在学习如何使用可变参数模板。基本上我想做的是采用一个包含类型String
元素的STLContainer
。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的答案,因为它似乎是最"通用证明"的解决方案,并提供了对我的代码的见解。但是,我想说@Walter的答案同样不错。虽然@max66的答案是解决问题的最简单答案,但最初的问题是我试图错误地描述 STL 容器。
尝试用这种方式编写泛型代码注定会失败,因为在一般情况下容器不能用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;
}
怎么样
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)
您的代码必须如下所示:
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
,无char16_t
,...)。还有一些在这里不那么成问题的地方。
该函数可以更通用:
没有保修,因为我很累,但无论如何...
如果你的代码要求类型是可迭代的,你首先不需要知道 String 的类型。您可以将其作为取消引用容器迭代器的衰减结果。通过将std::begin
和std::end
拖到作用域中,可以为免费的开始和结束函数启用 ADL,同时仍通过 std 函数捕获成员函数。
首先是一些标头和一个帮助程序类:
#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','; };
}
现在,我们尝试使用启用 ADL 的迭代来实现as_comma_list
,并且对容器或字符串的模板布局没有任何约束。
template <class C>
auto as_comma_list(C&& c)
{
using std::begin;
using std::end;
using string_type = std::decay_t<decltype(*begin(c))>;
using char_type = std::decay_t<decltype(*begin(*begin(c)))>;
string_type result;
auto const ec = end(c);
for (auto it = begin(c); it != ec; )
{
result += *it;
if (++it != ec)
{
result += detail::comma<char_type>::c;
}
else break;
}
return result;
}
注意:此示例要求 String 类型也是可迭代的(这很常见),并且在循环中具有第二个分支,在这里处理数十亿个字符串时可能会更慢。
- 在顶点着色器中使用 OpenGl 的未声明标识符,我在顶点着色器中绘制三角形时遇到问题
- Google protobuf 时间戳未声明标识符,在 Windows 上具有C++
- 我的函数调用 (C++) 中的未声明标识符
- 具有继承的未声明标识符(运算符 ostream)
- 无法确定 IDE 在 C++ 中说出未声明标识符的原因
- 错误 C2065:'lO':用于声明向量值的未声明标识符?
- 可变参数模板的未声明标识符
- 动态变量上的c++MACRO未声明标识符
- 指向对象的指针的未声明标识符向量
- 简单C++程序上的多个未声明标识符
- C++类"未声明标识符"
- 计算文本文件中的整数数(使用 fin>>x 的未声明标识符)
- 编译器错误 xcode 未声明标识符 C++
- 直接 X 11 纹理 FX 文件错误 X3004 未声明标识符"input"
- GCC 未声明标识符"_asm"
- ios_base类的C++未声明标识符
- 未声明标识符SQL_SS_TABLE
- 使用arrayfire的未声明标识符
- 未声明标识符和标识符未定义是什么意思?如何修复错误
- 在 MacOS 上使用 OpenMPI C++语法时未声明标识符'MPI'