You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CRTP中间类无法访问祖父类成员的原因探究

#include <iostream>
#include <string>

template<typename T>
class animal
{
    public:
        std::string print()
        {
            return static_cast<T*>(this)->impl_print();
        };

    protected:
        inline const static std::string verb = "says ";  
};

template<typename T>
class pet : public animal<pet<T>>
{

    public:
        std::string impl_print()
        {
            return verb + static_cast<T*>(this)->impl_print();
        };

        inline const static std::string excite = "!"; 
};

class cat : public pet<cat>
{
    public:
        std::string impl_print()
        {
            return "meow" + excite;
        };
};

class dog : public pet<dog>
{
    public:
        std::string impl_print()
        {
            return "WOOF" + excite;
        };
};

int main()
{

    cat a;
    dog c;

    std::cout<<a.print()<<std::endl;
    std::cout<<c.print()<<std::endl;

    return 0;
}

上述代码在GCC13编译时出现“'verb' was not declared in this scope”错误。为何CRTP继承链末端的类可访问父类成员,而中间类却无法访问自身父类(祖父类)的成员?


问题原因

这是模板继承中的依赖名称查找规则导致的:

  • 中间类pet<T>继承的基类是animal<pet<T>>,这个基类的类型依赖于模板参数T(属于「依赖基类」)。在模板类的成员函数中,编译器在未完成模板实例化前,不会主动去查找依赖基类的成员,所以直接写verb会被判定为未声明的符号。
  • 末端的cat/dog继承的是pet<cat>/pet<dog>——这是模板实例化后的具体类,不属于依赖模板参数的基类。编译器处理这类「非依赖基类」时,会直接查找其成员,因此excite可以正常访问。

修复方法

有两种可行的修复方式:

  1. 用this->明确指向基类成员:
std::string impl_print()
{
    return this->verb + static_cast<T*>(this)->impl_print();
};
  1. 通过基类名限定成员:
std::string impl_print()
{
    return animal<pet<T>>::verb + static_cast<T*>(this)->impl_print();
};

内容的提问来源于stack exchange,提问作者Treeman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 04:35:28