动态多态性对于对象来说是合理的,但对于算法来说却非常糟糕。对于算法,您最好使用静态多态性。如果你觉得你想要一个容器系统支持operator+()
它们,只要确保它们以某种方式引用一个命名空间并operator+()
在这个命名空间中定义一个合适的。例如,您可以使用从具有运算符的命名空间中的某些内容继承std::vector<T, A>
的分配器。A
下面是这种方法的一个例子。
这个想法基本上是让命名空间实现合适的运算符。例如,addable
实现operator+()
和printable
实现operator<<()
。除非类型以某种方式引用它们,否则不会查看这些名称空间,例如通过从该名称空间中的类型继承或通过使用继承这些类型之一的类型的模板参数。这种查找机制称为参数相关查找。因此,这两个命名空间都提供了一个空的struct tag {};
,在继承时不会花费任何成本。
为了获取以某种方式引用这些命名空间的容器,下面的代码只是创建了一个派生自这两种类型的分配器类模板。然后将此分配器与std::vector<T, A>
并std::list<T, A>
用于创建类型别名以轻松创建相应的容器。为了展示一切都很好,main()
只是演示了操作符的使用。
下面的代码在几个地方利用了 C++ 2011 来使符号更短一些。该原理也适用于 C++ 2003。主要是使用类型别名和初始化列表不起作用。
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>
#include <vector>
namespace addable
{
struct tag {};
template <typename T0, typename T1>
T0 operator+ (T0 const& c0, T1 const& c1)
{
T0 rc;
std::transform(c0.begin(), c0.end(),
c1.begin(),
std::back_inserter(rc),
std::plus<typename T0::value_type>());
return rc;
}
}
namespace printable
{
struct tag {};
template <typename T, typename = typename T::value_type>
std::ostream&
operator<< (std::ostream& out, T const& value)
{
out << "[";
if (!value.empty()) {
std::copy(value.begin(), value.end() - 1,
std::ostream_iterator<typename T::value_type>(out, ", "));
out << value.back();
}
return out << "]";
}
}
template <typename T>
struct my_allocator
: addable::tag
, printable::tag
, std::allocator<T>
{
};
template <typename T>
using my_vector = std::vector<T, my_allocator<T>>;
template <typename T>
using my_list = std::vector<T, my_allocator<T>>;
int main()
{
my_vector<int> v({ 1, 2, 3, 4 });
my_list<int> l({ 2, 3, 4, 5 });
my_vector<int> rc = v + l;
std::cout << v << " + " << l << " = " << (v + l) << "\n";
}