为什么 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 的行为是否不同。