【问题标题】:Is it possible to have C++ template function which takes any collection of type T?是否有可能拥有采用任何类型 T 集合的 C++ 模板函数?
【发布时间】:2015-06-06 22:02:08
【问题描述】:

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

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);

Function that takes an STL iterator over ANY container of a elements of a specific type

【问题讨论】:

  • "要求那个 T"...那个 T 什么?
  • 修正了上面的句子。
  • 这是为了提供重载或提供更好的错误消息吗?
  • 如果您尝试使用这些函数并且它们对于 T 不存在,则代码将无法编译。有什么问题?
  • 您要查找的内容称为"concepts"。由于各种原因,他们从未将其纳入任何 C++ 规范,而且可能永远不会。

标签: c++ templates iterator


【解决方案1】:

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

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

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

【讨论】:

  • 这不是检查范围内可用性的正确方法。
  • @T.C.你是说也应该检查像*std::begin(bobs) 这样的表达式吗?
  • 并非如此。我指的是ADL找到正确的begin()end()的情况。
  • @T.C.啊,对。我忘记了基于范围的 for 的 begin-expr 并不完全等同于 std::begin...
  • @T.C. this 是 ADL 开始/结束的正确实现吗?
【解决方案2】:

C++ 概念Container 有一个成员类型value_type 包含元素的类型,因此您可以像使用迭代器一样使用SFINAE - 它更简单,因为您不需要使用@987654323 @:

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>>
{
    // ...
}

【讨论】:

    【解决方案3】:

    是的。这是可能的。

    作为Ed S. comment,只需使用您在问题中编写的相同功能即可。如果bobs 没有begin()end(),那么编译器将通过生成错误来通知您。
    Demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-03
      • 2010-09-11
      • 2019-08-22
      • 2023-01-28
      • 2011-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多