处理特定类型元素的任何容器的非模板函数
Non-template function that processes any container of elements of specific type
我想要一个标题中描述的函数。
我注意到,STL算法与包含任何类型(int、double)元素的任何类型(列表、向量等)的容器一起工作,通过使用迭代器类型作为模板参数来提供泛型,例如
template<typename _II, typename _OI>
inline _OI
copy(_II __first, _II __last, _OI __result)
这是一个很好的方法,直到算法适用于任何类型的元素。元素类型的唯一要求是它必须具有复制构造函数。
但假设我们有一个混凝土类型的
class MyElement
{
public:
void doSomethingWithElement();
};
并且我们想要通过调用函数CCD_ 1来实现处理该类型的多个元素的函数。
编写接收特定类型容器的函数不是很方便,因为许多容器都以相同的方式处理(例如迭代器),如果需要处理不同类型的容器,我们将被迫复制代码。编写模板很好,但它看起来很难看,因为我们必须在声明它的地方(在头文件中)实现函数。此外,当我们只想处理一种类型的元素时,参数化这种类型并不是实现目标的正确方法。
我一直在考虑可以像一样使用的迭代器接口
void processContainer(IIterator<MyElement> begin, IIterator<MyElement> end);
如果这个迭代器有在派生类中实现的纯虚拟运算符++和运算符*,我们可以将这些对象传递给processContainer
。但有一个问题:如果IIterator是抽象类,我们无法在processContainer
的实现中实例化它,如果我们将指针传递给IIterator,这个函数将能够修改它。
有人知道还有其他黑客可以做到这一点吗?或者还有比上面这些更好的方法吗?提前谢谢。
更简单的方法是忽略限制,只将函数实现为任何迭代器的模板。如果迭代器没有引用类型,那么用户将在"类型X没有doSomethingWithElement
成员函数"的行中收到一条可怕的错误消息。
下一步是提供一个static_assert
,该函数仍然采用任何迭代器(这意味着它将参与任何类型的重载解析),但错误消息的信息量会稍大。
此外,您可以决定使用SFINAE来消除候选集合中的过载。虽然SFINAE是一把美丽的金锤,但我不确定你手头是否有合适的钉子。
如果你真的想更进一步,你可以看看Adobe库中的any_iterator
,作为如何对迭代器类型执行类型擦除以避免模板的例子。这种方法的复杂性比以前的任何方法都高出几个数量级,运行时成本也会更高,提供了更干净的ABI和更小的代码大小的唯一优势(不同的迭代器可以传递给单个函数)。
您可以使用std::for_each():http://www.cplusplus.com/reference/algorithm/for_each/
完整代码:
void callDoSomething(MyElement &elem)
{
elem.doSomething();
}
int main()
{
std::vector<MyElement> vec(100);
std::for_each(vec.begin(), vec.end(), callDoSomething);
}
你不能完全做你想做的事情。你可以使用enable_if
来限制函数的可用性:
template < typename Container >
typename enable_if<is_same<typename Container::value_type, MyElement>,void>::type processContainer(Container c)...
如果不更改迭代器接口,就不可能创建一个具有完整迭代器功能(包括复制自身的能力)的抽象迭代器。但是,您可以使用抽象基类实现迭代器功能的子集:
#include <iterator>
#include <vector>
#include <list>
template<typename T>
struct AbstractIterator
{
virtual bool operator!=(const AbstractIterator<T>& other) const = 0;
virtual void operator++() = 0;
virtual T& operator*() = 0;
};
template<typename Iterator>
struct ConcreteIterator : AbstractIterator<typename std::iterator_traits<Iterator>::value_type>
{
typedef typename std::iterator_traits<Iterator>::value_type value_type;
Iterator i;
ConcreteIterator(Iterator i) : i(i)
{
}
virtual bool operator!=(const AbstractIterator<value_type>& other) const
{
return i != static_cast<const ConcreteIterator*>(&other)->i;
}
virtual void operator++()
{
++i;
}
virtual value_type& operator*()
{
return *i;
}
};
template<typename Iterator>
ConcreteIterator<Iterator> wrapIterator(Iterator i)
{
return ConcreteIterator<Iterator>(i);
}
class MyElement
{
public:
void doSomethingWithElement();
};
void processContainerImpl(AbstractIterator<MyElement>& first, AbstractIterator<MyElement>& last)
{
for(; first != last; ++first)
{
(*first).doSomethingWithElement();
}
}
template<typename Iterator>
void processContainer(Iterator first, Iterator last)
{
ConcreteIterator<Iterator> wrapFirst = wrapIterator(first);
ConcreteIterator<Iterator> wrapLast = wrapIterator(last);
return processContainerImpl(wrapFirst, wrapLast);
}
int main()
{
std::vector<MyElement> v;
processContainer(v.begin(), v.end());
std::list<MyElement> l;
processContainer(l.begin(), l.end());
}
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为什么我不能在 C++ 中的特定函数重载中调用同一函数的任何其他重载?
- C++模板函数,用于比较任何无符号整数和有符号整数
- 是否有任何建议来统一函数类型限定符并简化可恶的函数类型?
- C++中是否有任何函数等同于python中字典的get函数?
- 用于检查值是否为其任何参数的帮助程序函数
- C++ - 声明指向返回任何类型并获取任意数量参数的函数的指针
- VkSurfaceKHR 指针的值在函数调用后更改,无需任何显式赋值
- 类和构造函数中的函数根本不起作用,并且不返回任何错误
- 不执行任何操作的函数调用C++
- 如何检测除整数以外的任何内容是否传递给我的类构造函数?
- 为什么 c++ 中的 main() 函数不采用除 int 和 void 之外的任何其他返回类型
- 检查模板中 nullptr 的函数指针,了解任何类型的可调用对象
- f 是指向函数的指针,该函数采用 int,并返回指向不带任何内容并返回双精度的函数的指针
- 如何制作可以接受任何类型的参数的 std::函数和 lambda
- 在调用其析构函数之前,是否有任何实际理由检查某些东西是否可破坏?
- 给定一个 3 x 3 矩阵或任何 n x n 矩阵,为什么我的以下函数找不到对角线差异?
- 接受任何 STL 容器的函数
- C++:单向跳转到函数.任何替代方案
- 从析构函数调用虚拟函数-任何解决方法