使用CRTP时的可见性问题

时间:2016-08-03 07:49:47

标签: c++11 crtp

这是我能提出的最小例子:

template <typename T>
struct Util
{
    using Type = int;
};

struct A
{
    struct B : public Util<B> {
        void fun(Type) {}
    };
};

template <typename T>
struct C
{
    struct D : public Util<D> {
        void fun(Type) {}
    };
};

int main()
{
    A::B{}.fun(0);
    C<int>::D{}.fun(0);
}

A::BC::D之间的唯一区别是C是模板。

struct C::D无法编译,并出现以下错误:

test_cpp.cpp:18:18: error: ‘Type’ has not been declared
         void fun(Type) {}
                  ^~~~

为什么这不能编译?我如何进行编译?

假设Util来自外部库并且我无法更改它(如果你有勇气的话,那就是boost::iterator_facade。)

1 个答案:

答案 0 :(得分:3)

此时:

template <typename T>
struct C
{
    struct D : public Util<D> {
        void fun(Type) {} // <-- here
    };
};

编译器无法知道<{em> * * Type需要来自Util<D>的范围。调用基类成员函数也是同样的问题,需要使用this->明确限定,否则无法找到它们。

您应该能够通过明确限定类型来解决此问题:

void fun(typename Util<D>::Type) {}

请参阅complete snippet on Coliru

差异背后的原因是,正如@ etam1024在评论中正确指出的那样,在A::B中,Type是非依赖名称,而在C::D中它是依赖名称。有关基类成员函数this answer的成员函数限定的类似情况的解释,请参阅。

*在我看来,编译器可以知道在哪里寻找Type,但语言规则说它看起来并不那么远。注意我可能会忽略特殊情况,编译器无法推断出这种情况,因此导致需要完全koalafication的一般情况。