为什么 CRTP(奇怪的递归模板模式)试图选择另一个私有库 class 的另一个同名函数?
Why is CRTP(curiously recursive template pattern) tries to choose another same name function of another private base class?
我正在学习 C++ 中的 CRTP(奇怪的递归模板模式)。
为了学习CRTP我做了如下代码
代码只是试图从一个基 class 通过另一个基 class 为 CRTP 获取迭代器。
问题是 gcc 编译器无法 select 下面的 test_get_iterator_by_crtp() 中的函数 GET_CONTAINRE_ITERATOR_CRTP::begin()。似乎 gcc 混淆了 GET_CONTAINRE_ITERATOR_CRTP<(int)> 和 ContainerIterator<(int)> 的 begin() 因为当我更改 GET_CONTAINRE_ITERATOR_CRTP<(int)>::begin() 的名称时错误消失了到 begin_another().
我预计 ci.template 开始(); below 不能是 ContainerIterator::begin() 因为它是作为私有基础 class 实现的,我们不能直接访问它。
请有人告诉我为什么 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
您应该明确告诉编译器基本模板 class 将实现方法 begin()
。在 CI
class 中,您可以通过向 public 部分添加一条 using
指令来实现:
using GET_CONTAINRE_ITERATOR_CRTP<CI>::begin;
默认情况下,编译器会合理建议 GET_CONTAINRE_ITERATOR_CRTP
模板的某些特化可以在没有 begin()
方法的情况下实现。
有关更多信息,您可以参考 Scott Meyers 的第 43 项 ("Effective C++")
更新:
using GET_CONTAINRE_ITERATOR_CRTP<CI>::begin;
会有帮助。但这种行为的主要原因是 GCC 完成 'name lookup' 和 'access checking' 的顺序。根据标准:The access rules (Clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded.
这会导致 begin
名称不明确的问题。目前尚不清楚 Clang 的行为是否不同。
我正在学习 C++ 中的 CRTP(奇怪的递归模板模式)。
为了学习CRTP我做了如下代码
代码只是试图从一个基 class 通过另一个基 class 为 CRTP 获取迭代器。
问题是 gcc 编译器无法 select 下面的 test_get_iterator_by_crtp() 中的函数 GET_CONTAINRE_ITERATOR_CRTP::begin()。似乎 gcc 混淆了 GET_CONTAINRE_ITERATOR_CRTP<(int)> 和 ContainerIterator<(int)> 的 begin() 因为当我更改 GET_CONTAINRE_ITERATOR_CRTP<(int)>::begin() 的名称时错误消失了到 begin_another().
我预计 ci.template 开始(); below 不能是 ContainerIterator::begin() 因为它是作为私有基础 class 实现的,我们不能直接访问它。
请有人告诉我为什么 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
您应该明确告诉编译器基本模板 class 将实现方法 begin()
。在 CI
class 中,您可以通过向 public 部分添加一条 using
指令来实现:
using GET_CONTAINRE_ITERATOR_CRTP<CI>::begin;
默认情况下,编译器会合理建议 GET_CONTAINRE_ITERATOR_CRTP
模板的某些特化可以在没有 begin()
方法的情况下实现。
有关更多信息,您可以参考 Scott Meyers 的第 43 项 ("Effective C++")
更新:
using GET_CONTAINRE_ITERATOR_CRTP<CI>::begin;
会有帮助。但这种行为的主要原因是 GCC 完成 'name lookup' 和 'access checking' 的顺序。根据标准:The access rules (Clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded.
这会导致 begin
名称不明确的问题。目前尚不清楚 Clang 的行为是否不同。