Variadic模板的未声明标识符

时间:2017-09-15 20:26:57

标签: 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 ... 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容器。

3 个答案:

答案 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)

但让我们来看看代码的含义:

  1. 类型STLContainer必须采用模板参数。如果我写了一个类simplestringvector(我知道这不是通用的,但没有人不能阻止我:))你的代码对我不起作用。

  2. STLContainer类型必须提供begin()end()成员。 (没有免费功能;没有std::beginstd::end

  3. String类型必须提供pop_back()成员。

  4. String类型必须定义operator+=,且必须能够处理包含char的字符串文字(无wchar_t,无{{1} },...)。

  5. 其他不太重要的问题。

  6. 该功能可以更通用:

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

    如果您的代码要求类型可以迭代,那么您首先不需要知道String的类型。您可以将其作为解除引用容器迭代器的衰减结果。通过将char16_tstd::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类型也是可迭代的(这是非常常见的),并且它在循环中有第二个分支,在这里处理数十亿个字符串时可能会更慢。