我正在寻找一种方法来提供一个带模板(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
的容器,但不接受具有不同元素类型的容器?
最佳, 本
答案 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
,就会匹配list
,deque
或int
。
答案 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){
}
有这个属性。