我当时(可能不正确)假设 C++ 中的非成员函数不会根据其参数类型进行分派(dispatch)。但是在阅读了 iterator_category
之后,我似乎可以根据其参数的类别类型调用一个函数,并且该调用还处理继承。例如,如果我只编写随机访问迭代器和输入迭代器的实现,所有使用非随机访问迭代器的调用都将转到接受输入迭代器的函数。这是书中的一个简短示例
template <class T>
foo(T a) {
foo(a, iterator_traits<T>::iterator_category());
}
template <class T>
foo(T a, random_access_iterator_tag) { \\body}
template <class T>
foo(T a, input_iterator_tag) { \\body}
// presumably this works even for
// ostream_iterator<int> i(cout);
// foo(i);
这种调度是普遍正确的还是特例?
如果我的实现不详尽,编译器是否应该警告我,例如在基于迭代器类别的示例中,如果我只给出了随机访问迭代器和双向迭代器的实现,编译器是否应该提示未涵盖输出迭代器.
这也是我第一次遇到参数只是类型而不是对象/实例的函数。那么我是否可以将具有内置或用户定义类型的函数定义为其参数之一而不指定该类型的实例/对象的名称?
下面似乎是CRTP的替代方案,实现编译时多态性。这是正确的解释吗
template<class T>
int foo(T a) {
foo(a, a::type());
}
int foo(int a, base) { \\body }
int foo(int a, derived) { \\body }
最佳答案
重载函数调用通过参数的static 类型来解析(这对于成员函数和非成员函数都是如此)。
所以:
class Base {};
class Derived : public Base {};
void foo(Base &b) {}
void foo(Derived &d) {}
Base b;
Derived d;
Base &r = d;
foo(b); // Calls first overload
foo(d); // Calls second overload
foo(r); // Calls first overload
更新
因此在您的新代码片段中,参数不是类型,它们只是“匿名的”;它们没有关联的变量名。
这一切都在编译时解决。 iterator_traits<T>::iterator_category
是一个 typedef(它将通过 T
模板依赖于 iterator_traits<T>
)。 iterator_traits<T>::iterator_category()
正在调用构造函数,以创建该类型的新临时对象,该对象用作“虚拟”参数。然后编译器将该调用解析为正确的重载。鉴于此参数是一个虚拟参数,因此函数内不需要变量名。
关于c++ - 基于非成员函数的参数进行调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7414770/