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

Using nested class of template parameter in CRTP

本文关键字:参数 嵌套 CRTP      更新时间:2023-10-16

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

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

如果我声明一个类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;
}

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

class B : public T<B>
{
public:
    class Nested
    {
    public:
        int i;
    };
    Nested nested;
};

编译上述代码失败,错误为:"嵌套不是B的成员"

我想我理解发生了什么:在输入模板时,由于继承的原因,类B没有完全定义。

然而,我想知道是否有办法做这样的事情。。。

谢谢你的帮助。

您需要将get_nested的返回类型的解析推迟到调用为止。

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

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

另一种方法(由于C++14)是使用返回类型推导:

  auto& get_nested()    { return p.nested; }

我能够用简单的编译您的示例

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

另一种方法,使用与@ecatmur相同的技巧,但简单一点:

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

类似地,在这里编译器必须推迟对P::Nested的求值,直到调用get_nested()