【问题标题】:template for "AnySTLContainer<int>" c++“AnySTLContainer<int>”的模板 c++
【发布时间】:2014-10-14 08:08:50
【问题描述】:

我正在寻找一种方法来提供一个函数,该函数采用模板化 (STL) 容器,但要求其元素为特定类型(例如 int)。

这些函数调用应该是有效的:

std::vector<int> Argument;
void foo( Argument );

std::list<int> Argument
void foo( Argument );

std::deque<int> Argument
void foo( Argument );

...etc

这些函数调用应该是无效的:

std::vector<float> Argument;
void foo( Argument );

std::list<double> Argument
void foo( Argument );

std::deque<char> Argument
void foo( Argument );

...etc

有没有办法对“foo”进行模板化,以便接受int 的容器,但不接受具有不同元素类型的容器?

最好, 本

【问题讨论】:

  • 只是检查一下,你真的需要一个容器吗?单纯的迭代器不起作用吗?
  • 顺便说一句:它必须是标准库容器,还是int 的任何容器足够好?甚至是不可变的序列?

标签: c++ templates stl template-argument-deduction


【解决方案1】:

STL 容器有typedefvalue_type,所以你可以使用它。

那你可以用static_assert禁止:

template <typename Container>
void foo(const Container& )
{
    static_assert(std::is_same<int, typename Container::value_type>::value, "expect int type");
}

或通过 SFINAE

template <typename Container>
typename std::enable_if<std::is_same<int, typename Container::value_type>::value>::type
foo(const Container& )
{
}

【讨论】:

  • 您能否解释一下,为什么/何时比纯粹基于模板的问题解决方案更受青睐?
  • @SH:static_assert 给出更好的错误消息,SFINAE 禁用不匹配的模板,因此不是重载的一部分(例如,您可以为浮动容器添加其他重载)。跨度>
【解决方案2】:

使用标准库语义:

  • 将一对迭代器传递给foo,而不是容器:它使您的函数更加更通用
  • 使用std::iterator_traits&lt;Iterator&gt;::value_type 获取值类型
  • static_assert 迭代器的值类型为 int(或您想要的任何类型)

示例:

#include <list>
#include <vector>

template<typename Iterator>
void foo(Iterator begin, Iterator end)
{
    static_assert(std::is_same<int, typename std::iterator_traits<Iterator>::value_type>::value, 
                                "Invalid value type : must be int");
}

int main() {
    std::list<int> l1;
    std::vector<int> v1;

    foo(std::begin(l1), std::end(l1)); // OK
    foo(std::begin(v1), std::end(v1)); // OK

    std::vector<float> v2;
    foo(std::begin(v2), std::end(v2)); // Doesn't compile
}

Live demo

注意:

  • 如果 foo 需要访问容器的特定成员函数(如 Deduplicator 所述,这可能是出于性能原因),那么您可能需要坚持使用 Container 参数:

示例:(注意获取 value_type 的区别,正如 MooingDuck 所指出的,这是使其与数组一起使用所必需的):

template <typename Container>
void foo(const Container& c)
{

    static_assert(std::is_same<int, std::iterator_type<decltype(std::begin(c))>::value_type>::value, "Invalid value type : must be int");

   // Use c member function(s)
}

【讨论】:

  • 视情况而定。使用迭代器可能会禁止使用正确的算法,例如 map.find
  • @Deduplicator 同意了,但是这里的 OP 有一个非成员模板功能,所以我认为它不适用。
  • @quantdev 对于 C++11,答案是可以的。但是,值得注意的是,既然 C++14 已经出现,概念是约束类型的最佳方式。
  • @black 除了概念没有进入 C++14
【解决方案3】:

您可以像这样简单地使用 Sfinae:

#include <type_traits>
#include <utility>

template <typename Container>
typename std::enable_if< std::is_same< typename Container::value_type, int >::value,
void >::type foo(Container& c) {
  /* code here */
};

如果容器没有与“int”相同的值类型,它将从“foo”的重载集中删除。您还可以使用其他特征,例如 is_convertible 来更好地接受相关类型。使用没有 int 作为值的容器调用 foo 将被编译器报告为没有合适的重载候选者。

如果你没有 C++11 支持,我上面使用的东西可以在 Boost 中作为 C++98/03 的替代品使用。

【讨论】:

    【解决方案4】:

    另一种解决方案,使用模板模板参数

    template<template<typename, typename...> class Container, typename... Params>
    void foo(Container<int, Params...> const&)
    {
      ...
    }
    

    只要容器中元素的类型是int,这将匹配vectorlistdeque

    Live demo

    【讨论】:

      【解决方案5】:

      假设你想要一个可迭代的范围:

      template<class I>
      using value_type_t=typename std::iterator_traits<I>::value_type;
      

      在 C++14 中已过时:

      template<class T>using decay_t=typename std::decay<T>::type;
      template<bool b,class T=void>using enable_if_t=typename std::enable_if<b,T>::type;
      

      然后:

      namespace adl_details{
        using std::begin;
       template<class C>using iterator_type=decay_t<decltype(begin(std::declval<C>()))>;
      }
      using adl_details::iterator_type;
      
      
      template<class C>
      enable_if_t<std::is_same<int, value_type_t<iterator_type_t<C>>>::value>
      foo(C&& c){
      }
      

      有那个属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多