是否可以使用 C++ 模板函数来获取类型 T 的任何集合?

问题描述 投票:0回答:4

我想知道是否有一种方法可以创建一个模板函数,该函数引用特定类型的任何集合。即类似:

class Bob
{
  public:
  int age;
  int height;
}

template<class T>
void functionWhichIteratesOverBobs(T &bobs)
{
    int totalAge = 0;
    for(auto &bob: bobs)
    {
         totalAge += bob.age;
    }
}

基本上有没有一种方法可以在模板函数的定义中要求 T 有一个 begin() 和 end() 函数,它们返回一个迭代器给 T。

我已经看到了以下问题,但这需要一个带有开始和结束的函数,即

std::vector<Bob> bobs;
functionWhichIteratesOverBobs(bob.begin(), bob.end());

当我想要的是:

std::vector<Bob> bobs;
functionWhichIteratesOverBobs(bobs);

在特定类型元素的任何容器上采用 STL 迭代器的函数

c++ templates iterator
4个回答
1
投票

如果您希望保持过载集不受污染,请使用表达式 SFINAE,如下所示:

template<class T>
void functionWhichIteratesOverBobs(T &bobs)
  -> decltype(std::begin(bobs), std::end(bobs), void()) {
    // [..Range based for over bobs..] 
}

请记住,如果给出了错误的参数,您显示的函数模板将不会在没有错误的情况下实例化,因此这目前是多余的 - 直到您开始重载

functionWhichIteratesOverBobs


0
投票

C++ 概念 Container 有一个成员类型

value_type
所包含元素的类型,因此您可以像使用迭代器一样使用 SFINAE - 甚至更简单,因为您不需要使用
iterator_traits

template<class T>
auto functionWhichIteratesOverBobs(T &bobs)
    -> std::enable_if_t<std::is_same_v<typename T::value_type, Bob>>
{
    // ...
}

请注意,这不适用于原始数组;如果你想让它们起作用,你可以使用

decltype(std::begin(bobs))
iterator_traits
:

template<class T>
auto functionWhichIteratesOverBobs(T &bobs) -> std::enable_if_t<std::is_same_v<
    typename std::iterator_traits<decltype(std::begin(bobs))>::value_type, Bob>>
{
    // ...
}

0
投票

是的。这是可能的。

作为 Ed S. comment,只需使用您在问题中编写的相同函数即可。如果

bobs
没有
begin()
end()
那么编译器将通过生成错误来通知您。
演示


0
投票

在 C++ 20 中,您可以使用范围概念:

#include <ranges>
template<std::ranges::range T>
void functionWhichIteratesOverBobs(T &bobs)

这将检查 T 是否是一个范围,即有开始和结束。

范围库中有更细粒度的概念。

https://en.cppreference.com/w/cpp/ranges#Range_concepts

我发现这比 SFINAE 更具可读性

© www.soinside.com 2019 - 2024. All rights reserved.