CRTP变量inizializatin中的衍生类

发布于 2025-01-22 15:02:58 字数 1439 浏览 2 评论 0原文

考虑以下实现CRTP的代码,

#include <iostream>

template <typename T>
class base {
    int n;
    base() {}
    friend T;
public:
    explicit base(int _n) : n{_n} {}
    void print() const { static_cast<const T&>(*this).whoami(); }
};

class derived : public base<derived> {
public:
    void whoami() const { std::cout << n << std::endl; }
};

int main()
{
    base<derived> a{6};
    a.print();
}

如预期,代码打印6。

默认的构造函数base :: base()将离开成员字段n非专业化。但是,由于它是privatebasefriend derived,因此只有derived使用base :: base()(具体来说,在其编译器生成的默认文件中)。但是派生没有公共构造函数,因此永远不会实例化。因此,从n的初始化点起,代码似乎是安全的,尽管代码的一部分实际上没有执行正确的初始化。

所以我想知道:上面的代码中是否有陷阱?

注意

请注意,它不仅仅是学术的问题。在现实情况下,base的成员可能没有明智的默认初始化,并且由base的构造函数初始化,该构建器采用一系列参数。这些参数只能在运行时确定,并在main()中用于实例base&lt; derived&gt;

class base {
public:
    base(int param1, char *param2);
};

如果base没有默认构造函数,则需要一个派生的构造函数,该构建器调用base类base&lt; derived&gt;的构造函数。如果没有明智的默认参数,则将其称为 “随机”参数

class derived : public base<derived> {
    derived() : base<derived>(42, "unexisting_file") { }
};

Consider the following code implementing CRTP

#include <iostream>

template <typename T>
class base {
    int n;
    base() {}
    friend T;
public:
    explicit base(int _n) : n{_n} {}
    void print() const { static_cast<const T&>(*this).whoami(); }
};

class derived : public base<derived> {
public:
    void whoami() const { std::cout << n << std::endl; }
};

int main()
{
    base<derived> a{6};
    a.print();
}

The code prints 6 as expected.

The default constructor base::base() would leave the member field n uninitialized. However, since it is private and base is friend to derived, only derived uses base::base() (specifically, in its compiler-generated default contructor). But derived has not public constructors, so it is never instantiated. So the code seems to be safe from the point of the initialization of n, though there is a part of the code that, effectively, does not perform the correct initialization.

So I wonder: is there a pitfall in a code like above?

Note

Please notice that the question it not merely academic. In a real-world case, the members of base may not have a sensible default initialization, and are initialized by a constructor of base that takes a series of parameters. These parameters can be possibly determined at runtime only, and used in main() to instantiate base<derived>.

class base {
public:
    base(int param1, char *param2);
};

If there is no default constructor for base, you need a constructor for derived that calls the constructor of the base class base<derived>. When this has no sensible default parameters, it would be very awkward to call it with
"random" parameters

class derived : public base<derived> {
    derived() : base<derived>(42, "unexisting_file") { }
};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文