“AnySTLContainer <int>”c ++ </int>的模板

时间:2014-08-20 20:16:49

标签: c++ templates stl template-deduction

我正在寻找一种方法来提供一个带模板(STL)容器的函数,但要求它的元素属于某种类型(例如int)。

这些函数调用应该是VALID:

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

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

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

...etc

这些函数调用应为INVALID:

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

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

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

...etc

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

最佳, 本

5 个答案:

答案 0 :(得分:13)

使用标准库语义:

  • 将一对迭代器传递给foo,而不是容器:它使您的功能更多更通用
  • 使用std::iterator_traits<Iterator>::value_type转到值类型
  • static_assert Iterator的值类型为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所述,出于性能原因可能会发生这种情况),那么您可能需要坚持{{1参数:

示例:(注意获取Container的区别,正如MooingDuck指出的那样,这需要使其适用于数组):

value_type

答案 1 :(得分:9)

STL容器包含typedef value_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& )
{
}

答案 2 :(得分:4)

你可以简单地使用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 */
};

将从&#34; foo&#34;的过载集合中删除如果容器的值类型与&#34; int&#34;相同。您还可以使用其他特征(如is_convertible)来更多地接受相关类型。使用没有int作为值的容器调用foo将被编译器报告没有合适的重载候选者。

如果您没有C ++ 11支持,我上面使用的内容可以作为C ++ 98/03替代版本在Boost中使用。

答案 3 :(得分:3)

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

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

只要容器中的元素类型为vector,就会匹配listdequeint

Live demo

答案 4 :(得分:0)

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

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){
}

有这个属性。