我正在学习c ++中的CRTP(奇怪的递归模板模式)。
我制作了以下代码来学习CRTP。
代码只是尝试从基类通过另一个CRTP基类获取迭代器。
问题是gcc编译器无法在下面的test_get_iterator_by_crtp()中选择函数GET_CONTAINRE_ITERATOR_CRTP :: begin()。似乎gcc混淆了GET_CONTAINRE_ITERATOR_CRTP<(int)>的begin()。和ContainerIterator<(int)>因为当我将GET_CONTAINRE_ITERATOR_CRTP<(int)> :: begin()的名称更改为begin_another()时,错误消失。
我期待ci.template begin();下面不能是ContainerIterator :: begin(),因为它是作为私有基类实现的,我们无法直接访问它。
请有人告诉我为什么begin()含糊不清。 如果我犯了一个容易犯的错误或误解,请原谅我。非常感谢你。
template <typename T>
class ContainerIterator : public std::vector<T> {
public:
auto begin(void) {
return std::vector<T>::begin();
}
};
template <typename Derived>
class GET_CONTAINRE_ITERATOR_CRTP {
public:
template <typename T>
auto begin(void) {
Derived* host = static_cast<Derived*>(this);
// The following line makes a compile error of ambiguous name, begin().
return host->template ContainerIterator<T>::begin();
}
};
// CI = Container Iterator
class CI : private ContainerIterator<int>, public GET_CONTAINRE_ITERATOR_CRTP<CI> {
public:
friend class GET_CONTAINRE_ITERATOR_CRTP<CI>;
};
void test_get_iterator_by_crtp(void) {
CI ci{};
auto it = ci.template begin<int>();
}
错误消息:
error: request for member ‘begin’ is ambiguous
答案 0 :(得分:2)
您应该明确告诉编译器基本模板类将实现方法begin()
。在CI
课程中,您可以向公共部门添加一条using
指令来完成此操作:
using GET_CONTAINRE_ITERATOR_CRTP<CI>::begin;
默认编译器公平地建议GET_CONTAINRE_ITERATOR_CRTP
temlate的某些特化可以在没有begin()
方法的情况下实现。
有关更多信息,请参阅Scott Meyers的第43项(&#34; Effective C ++&#34;)
<强> UPD:强>
using GET_CONTAINRE_ITERATOR_CRTP<CI>::begin;
会有所帮助。但是这种行为的主要原因在于名称查找的顺序&#39;和访问检查&#39;由GCC完成。根据标准:The access rules (Clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded.
这会导致模糊begin
名称出现问题。目前尚不清楚Clang表现不同。