C++ 变量模板的未声明标识符

C++ 变量模板的未声明标识符,c++,c++11,templates,variadic-templates,template-templates,C++,C++11,Templates,Variadic Templates,Template Templates,我还在学习如何使用可变模板。基本上,我想做的是获取一个STLContainer,它包含String类型的元素。STL容器不接受固定数量的参数,所以我尝试使用可变模板。如果我理解正确,我应该能够写下: /* Take a container of String and return a string of those elements separated by commas.*/ template < template <typename String, typename ... T

我还在学习如何使用可变模板。基本上,我想做的是获取一个
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;
}
/*获取一个字符串容器并返回由逗号分隔的元素组成的字符串*/
模板<模板类STLContainer>
字符串作为逗号列表(常量STLContainer和container)
{
字符串结果;
for(auto-it=container.begin();it!=container.end();it++)
{
结果+=*it;
结果+=“,”;
}
result.pop_back();//弹出最后一个逗号
返回结果;
}
然而,编译器(
Apple LLVM 8.1.0版
)指出:

错误:使用未声明的标识符“Traits”

非常感谢您的帮助

编辑:我最终选择了@Pixelchemist的答案,因为它似乎是最“通用证明”的解决方案,并提供了对我的代码的洞察。然而,我想说,@Walter的答案相当好。虽然@max66的答案是解决问题的最简单答案,但最初的问题是我试图错误地描述STL容器。

怎么办

template <template <typename...> class STLContainer,
          typename String, typename Traits> 
String as_comma_list(const STLContainer<String, Traits> &container)
那怎么办

template <template <typename...> class STLContainer,
          typename String, typename Traits> 
String as_comma_list(const STLContainer<String, Traits> &container)
您的代码必须如下所示: 现在,我们尝试将
实现为_comma_list
,使用支持ADL的迭代,并且对容器或字符串的模板布局没有任何约束

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;
}
模板
自动作为逗号列表(C&&C)
{
使用std::begin;
使用std::end;
使用字符串\u type=std::decation\u t;
使用char\u type=std::decation\u t;
字符串类型结果;
自动常数ec=结束(c);
对于(自动it=begin(c);it!=ec;)
{
结果+=*it;
如果(++it!=ec)
{
结果+=细节::逗号::c;
}
否则就断了;
}
返回结果;
}
注意:此示例要求字符串类型也是可编辑的(这是非常常见的),并且它在循环中有第二个分支,在这里处理数十亿个字符串时可能会慢一些。

您的代码必须如下所示: 现在,我们尝试将
实现为_comma_list
,使用支持ADL的迭代,并且对容器或字符串的模板布局没有任何约束

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;
}
模板
自动作为逗号列表(C&&C)
{
使用std::begin;
使用std::end;
使用字符串\u type=std::decation\u t;
使用char\u type=std::decation\u t;
字符串类型结果;
自动常数ec=结束(c);
对于(自动it=begin(c);it!=ec;)
{
结果+=*it;
如果(++it!=ec)
{
结果+=细节::逗号::c;
}
否则就断了;
}
返回结果;
}

注意:此示例要求字符串类型也是iterable(这是非常常见的),并且它在循环中有第二个分支,在这里处理数十亿字符串时可能会较慢。

尝试以这种方式编写泛型代码注定会失败,因为在一般情况下,容器不能被描述为
容器,想一想
map
,它有
value\u type=pair

在C++中,这种泛型编程通常是通过<代码>迭代器< /C> >(如标准库中的所有),例如

模板
在函数体中启用\u if//或使用静态\u assert()
作为逗号列表(开始、结束和结束)
{
字符串结果;
for(;begin!=end;++begin)
{
结果+=*开始;
结果+=“,”;
}
result.pop_back();
返回结果;
}

尝试以这种方式编写通用代码肯定会失败,因为在一般情况下,容器不能被描述为
容器
,请考虑
映射
,它具有
值\u type=pair

在C++中,这种泛型编程通常是通过<代码>迭代器< /C> >(如标准库中的所有),例如

模板
在函数体中启用\u if//或使用静态\u assert()
作为逗号列表(开始、结束和结束)
{
字符串结果;
for(;begin!=end;++begin)
{
结果+=*开始;
结果+=“,”;
}
result.pop_back();
返回结果;
}

Traits
不是一种类型;它是一个参数包。您需要展开参数包:
STLContainer
实际上,您也没有参数包;您需要
Traits
不在
STLContainer
的模板参数列表中,而是在
作为逗号列表的
STL容器通常不能被描述为
container
。考虑<代码> STD::MAP<代码>,它有<代码> ValueOyType=STD::配对< /COD>…>代码>特性> /COD>不是一种类型;它是一个参数包。您需要展开参数包:
STLContainer
实际上,您也没有参数包;您需要
Traits
不在
STLContainer
的模板参数列表中,而是在
作为逗号列表的
STL容器通常不能被描述为
container
。考虑<代码> STD::map < /COD>,它有<代码> ValueOyType=STD::配对< /代码>…有趣的概念,SimpIsiType;-]沃尔特-很有趣,不是吗:(?我已经使用了拼写检查器。谢谢!尽管我必须问一下,参考@Walter的答案。这会捕获所有STL容器吗?我测试了它,编译器成功地推断出
STLContainer
std::vector
String
std::String
@CarlosBrito-模板参数部分截取几乎所有STL容器(例外:
std::array
,因为它的第二个模板参数不是一个类型);但可能您不希望以相同的方式使用它们;我的意思是:向量和集合的
begin()
方法返回一个“指向”所包含(
String
)的迭代器元素;用于映射(orde)
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;
}
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;
}