从类模板派生的类的公共函数

发布于 2025-01-11 10:05:37 字数 1894 浏览 0 评论 0原文

我有一个具有以下类层次结构的程序:

struct TYPE_ONE { int i; };
struct TYPE_TWO { int i; };

template<typename T>
class Base
{
        public:
                int fun(int i);

};

template<typename T>
int Base<T>::fun(int i)
{
        return 42 * i;
}


class A : public Base<TYPE_ONE>
{
        public:
                void another_fun()
                {
                        fun(1);
                }
} a;

class B : public Base<TYPE_TWO>
{
        public:
                void another_fun()
                {
                        fun(2);
                }

} b;

int main()
{
        a.another_fun();
        b.another_fun();
}

如您所见,fun 不依赖于类型。不幸的是,编译器正在生成两个有趣的方法。每种类型一个。

$ nm --demangle ./a.out | grep fun
0000000000001150 W A::another_fun()
0000000000001174 W B::another_fun()
0000000000001198 W Base<TYPE_ONE>::fun(int)
00000000000011b0 W Base<TYPE_TWO>::fun(int)

有没有一种方法可以强制编译器为这两个类仅生成一个公共函数?

我发现我可以尝试通过将 fun 设为静态并向模板添加默认参数来解决此问题。类似于:

template<typename T=TYPE_ONE>
class Base
{
        public:
                static int fun(int i);

};

class A : public Base<TYPE_ONE>
{
        public:
                void another_fun()
                {
                        Base<>::fun(1);
                }
} a;

class B : public Base<TYPE_TWO>
{
        public:
                void another_fun()
                {
                        Base<>::fun(2);
                }

} b;

使用此编译器仅生成一个 fun 方法:

$ nm --demangle ./a.out | grep fun
0000000000001150 W A::another_fun()
000000000000116e W B::another_fun()
000000000000118c W Base<TYPE_ONE>::fun(int)

但是对于这个问题有更干净的解决方案吗?

I have a program with the following class hierarchy:

struct TYPE_ONE { int i; };
struct TYPE_TWO { int i; };

template<typename T>
class Base
{
        public:
                int fun(int i);

};

template<typename T>
int Base<T>::fun(int i)
{
        return 42 * i;
}


class A : public Base<TYPE_ONE>
{
        public:
                void another_fun()
                {
                        fun(1);
                }
} a;

class B : public Base<TYPE_TWO>
{
        public:
                void another_fun()
                {
                        fun(2);
                }

} b;

int main()
{
        a.another_fun();
        b.another_fun();
}

As you can see the fun doesn't depend on the type. Unfortunately compiler is generating two fun methods. One for each type.

$ nm --demangle ./a.out | grep fun
0000000000001150 W A::another_fun()
0000000000001174 W B::another_fun()
0000000000001198 W Base<TYPE_ONE>::fun(int)
00000000000011b0 W Base<TYPE_TWO>::fun(int)

Is there a way to force compiler to generate only one common function for both classes?

I see that I could try to workaround this by making fun static and adding default argument to the template. Something like:

template<typename T=TYPE_ONE>
class Base
{
        public:
                static int fun(int i);

};

class A : public Base<TYPE_ONE>
{
        public:
                void another_fun()
                {
                        Base<>::fun(1);
                }
} a;

class B : public Base<TYPE_TWO>
{
        public:
                void another_fun()
                {
                        Base<>::fun(2);
                }

} b;

With this compiler generates only one fun method:

$ nm --demangle ./a.out | grep fun
0000000000001150 W A::another_fun()
000000000000116e W B::another_fun()
000000000000118c W Base<TYPE_ONE>::fun(int)

But is there a cleaner solution for this issue?

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

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

舟遥客 2025-01-18 10:05:37

下面定义了两种不同的类型,它们恰好具有完全相同的实现:

struct TYPE_ONE { int i; };
struct TYPE_TWO { int i; };

这会误导人们认为 fun() 应该共享相同的代码。

但实际上,这是一个非常特殊的情况。由于这两种类型可以共享具有不同内存布局的符号 i,因此需要不同的机器代码来执行表面上相同的 i*42。

struct TYPE_ONE { int i; };
struct TYPE_TWO { int k,i; };

您甚至可能会遇到不同类型的情况,同样,机器代码将完全不同并且无法共享:

struct TYPE_ONE { int i; };
struct TYPE_TWO { double i; };

当然,编译器可以识别这些类型具有相同的布局并努力使用一些通用代码。但这根本不是义务。

如果模板类中有固定类型的公共部分,则应该将该公共部分重构为模板类的非模板基类。例如:

struct RealBase { 
    int i;
    int fun(int i); 
}; 

struct TYPE_ONE : RealBase {}; 
struct TYPE_TWO : RealBase {}; 

并相应地调整A和B。这里有一个 RealBase,无论您在其上构建什么模板。并且您的编译器自然只有一种 RealBase 实现。

The following defines two distinct types, that happen to have exactly the same implementation:

struct TYPE_ONE { int i; };
struct TYPE_TWO { int i; };

This misleads to think that fun() should share the same code.

But in reality, this is a very exceptional circumstance. Because the two types could share a symbol i with a different memory layout, that would require a different machine code to perform the apparently identical i*42.

struct TYPE_ONE { int i; };
struct TYPE_TWO { int k,i; };

You could even have the case of different types, where again, the machine code would be completely different and could not be shared:

struct TYPE_ONE { int i; };
struct TYPE_TWO { double i; };

Of course, the compiler could recognize that the types have an identical layout and make the effort of using some common code. But it's not at all an obligation.

If there is a common part in the template class with fixed types, you should refactor that common part into a non-template base to the template class. For example:

struct RealBase { 
    int i;
    int fun(int i); 
}; 

struct TYPE_ONE : RealBase {}; 
struct TYPE_TWO : RealBase {}; 

and adapt A and B accordingly. Here there is one RealBase, whatever template you build upon it. And your compiler would naturally have only one RealBase implementation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文