在CRTP中使用嵌套的模板参数类

shr*_*ike 5 c++

假设我定义了一个T使用模板参数的嵌套类的模板P,如下所示:

template<class P> class T
{
public:
    T(P& p) : p(p) {}
    P& p;
    typename P::Nested& get_nested()    { return p.nested; }
};
Run Code Online (Sandbox Code Playgroud)

如果我声明一个A包含一个名为的嵌套类的类Nested,我可以定义一个T<A>没有问题的类型的变量:

class A
{
public:
    class Nested
    {
    public:
        int i;
    };
    Nested nested;
};

void test2a()
{
    A a;
    a.nested.i = 1;
    T<A> t_a(a);
    t_a.get_nested().i = 2;
}
Run Code Online (Sandbox Code Playgroud)

现在,我想声明一个类B,以同样的方式,包含一个名为的嵌套类,Nested并继承自T<B>,如下所示:

class B : public T<B>
{
public:
    class Nested
    {
    public:
        int i;
    };
    Nested nested;
};
Run Code Online (Sandbox Code Playgroud)

编译上面的代码失败并出现错误:" 嵌套不是B的成员"

我想我理解发生了什么:在输入模板时,由于继承,B类未完全定义.

但是,我想知道是否有办法做这样的事情......

感谢帮助.

eca*_*mur 6

您需要推迟返回类型的分辨率,get_nested直到它被调用.

一种方法是使返回类型依赖于模板参数:

  template<typename unused = void>
    typename std::conditional<false, unused, P>::type::Nested&
    get_nested()    { return p.nested; }
Run Code Online (Sandbox Code Playgroud)

另一种方式(自C++ 14以来)是使用返回类型推导:

  auto& get_nested()    { return p.nested; }
Run Code Online (Sandbox Code Playgroud)


Pet*_*etr 4

我可以简单地编译你的示例

template<class P> class T
{
public:
    T(P& p) : p(p) {}
    P& p;
    auto& get_nested()    { return p.nested; }
};
Run Code Online (Sandbox Code Playgroud)

另一种方法,利用与@ecatmur相同的技巧,但更简单一些:

template<class R = P>
typename R::Nested& get_nested()    { return p.nested; }
Run Code Online (Sandbox Code Playgroud)

同样,这里编译器必须推迟对 的求值,P::Nested直到您调用get_nested().