【问题标题】:How to provide the function signature for a function taking iterators of stl containers?如何为采用 stl 容器迭代器的函数提供函数签名?
【发布时间】:2019-12-25 18:59:10
【问题描述】:

我想写一个函数my_func 可以这样调用,但不关心vstd::vector,它可以是任何STL 容器。有点像std::for_each:

std::vector<std::string> v = {...};
my_func(v.begin(), v.end());

但我无法弄清楚函数签名。

void my_func(??? i1, ??? i2)
{
  std::for_each(i1, i2, ...); // dumb example implementation
}

我不擅长模板编程,所以即使查看 std::for_each 的函数声明也无济于事。

是否有一个简单的实现,或者这从根本上会使模板变量变得混乱?

【问题讨论】:

  • 您必须使用模板。每个迭代器都是不同的类型。 C++ 库中的所有迭代器都没有通用的超类。

标签: c++ function templates stl c++14


【解决方案1】:

这取决于您希望函数的通用程度。如果迭代器类型必须匹配,那么

template <typename T>
void my_func(T i1, T i2)
{
    std::for_each(i1,i2,...); //dumb example implementation
}

就是你所需要的。如果您希望它们能够有所不同,那么您只需要另一个模板参数,例如

template <typename T, typename U>
void my_func(T i1, U i2)
{
    std::for_each(i1,i2,...); //dumb example implementation
}

最后,如果您不喜欢处理模板,您可以改用 lambda,让编译器为您处理。那会给你

auto my_func = [](auto i1, auto i2)
{
    std::for_each(i1,i2,...); //dumb example implementation
};

【讨论】:

  • 在我的用例中(在问题中),我必须在调用它时指定T 还是编译器会推断出这个?
  • @Mr.Boy 编译器会为你推断。
  • 关于声明 lambda 对象的好主意
  • @Mr.Boy 谢谢。 Lambda 非常有用。它们是我最喜欢的现代 C++ 特性之一。
  • @Mr.Boy 如果这是你想要的,你可以用template &lt;typename T&gt; void my_func(T const &amp; c) { std::for_each(c.begin(), c.end(),...); //dumb example implementation }做同样的事情
【解决方案2】:

你可以写一个模板函数

template<typename Iterator>
void my_func(Iterator startIter, const Iterator endIter)
{
  std::for_each(startIter, endIter, /* lambda */);
}

如果想知道如何传递std::for_each的第三个参数,可以再提供一个模板参数

const auto defaultCallable = [](auto element){ }; // does nothing
template<typename Iterator, typename Callable = decltype(defaultCallable)>
void my_func(Iterator startIter, const Iterator endIter, Callable func = {})
{
    std::for_each(startIter, endIter, func);
}

【讨论】:

    【解决方案3】:

    语法不是晦涩!以下方式在使用点使用范围for

    template <template<typename...> class Iterable, typename T>
    void foo(
        const Iterable<T>& y // the container
    ){
        for (auto&& e : y){
            // e is the 'thingy' in the container.
        }
    }
    

    您可以将任意类型的任何可迭代容器传递给foo

    【讨论】:

    • 将迭代器抽象出来的有趣方法,但不确定这是否是 OP 所说的“简单”(模板模板参数不是最容易访问的东西)
    • @foreknownas_463035818:我修复了缩进,来吧,这很容易!
    • 如果你希望它是通用的,T 需要是一个参数包。否则template&lt;typename&gt; class Iterable 会完成这项工作。但是我看不出这样做的好处,只是有一个带有const T &amp; y 参数的typename T。编辑:我想省略号的解决方案涵盖了 std::vector 这样的案例,它有多个模板参数,但只有第一个没有默认类型。但是一个简单的模板参数也可以涵盖这一点。
    • @foreknownas_463035818:但它是美丽的东西!也许这个答案不一定针对 OP:答案不一定是。
    • @Bathsheba 我担心的是,我不明白这个解决方案相对于单个模板参数的好处。 Example.
    猜你喜欢
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    相关资源
    最近更新 更多