我仍在学习如何使用可变参数模板。基本上,我想做的是一个包含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的答案,因为这似乎是最“通用的证明”解决方案,并且可以深入了解我的代码。但是,我想说@Walter的回答同样好。 @ max66的答案是解决问题的最简单方法,但最初的问题是我试图错误地描述STL容器。

最佳答案

您的代码必须如下所示:

template < template <class...> class STLContainer, class String, class ...Traits>
String as_comma_list(const STLContainer<String, Traits...> &container)


但是让我们看一下代码的含义:


类型STLContainer必须带有模板参数。如果我写了一个simplestringvector类(我知道这不是通用的,但是没有人不能阻止我:),那么您的代码将对我不起作用。
STLContainer类型必须提供begin()end()成员。 (没有免费功能;没有std::beginstd::end
String类型必须提供一个pop_back()成员。
String类型必须定义为operator+=,该类型必须能够处理包含char的字符串文字(无wchar_t,无char16_t,...)。
还有其他在这里问题不大的问题。


该函数可以更通用:

没有保修,因为我很累,但是无论如何...

如果您的代码无论如何都要求类型是可迭代的,则无需首先知道String的类型。您可以将其作为取消引用容器迭代器的衰减结果而获得。通过将std::beginstd::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类型也可迭代(这是非常常见的),并且它在循环中具有第二个分支,在此处处理数十亿个字符串时,它可能会比较慢。

关于c++ - 可变参数模板的未声明标识符,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46247045/

10-11 23:01
查看更多