为什么CRTP(奇怪的递归模板模式)试图选择另一个私有基类的另一个同名函数?

时间:2017-03-21 16:54:28

标签: c++ crtp

我正在学习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

1 个答案:

答案 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表现不同。