GCC 去虚拟化和仅内联第一个接口
GCC Devirtualization and Inlining only first Interface
我在下面的代码中发现了一个问题:
看起来 GCC 只能去虚拟化第一个接口 I_Udc。接口 GCC 无法将第二个接口去虚拟化 I_Uac。如果我先写 I_Uac,I_Uac 调用将被内联。
这是编译器资源管理器中的代码:
https://godbolt.org/z/z6WEoznfW
class I_Uac
{
public:
virtual float GetIUac() = 0;
};
class I_Udc
{
public:
virtual float GetIUdc() = 0;
};
class DataAcq final : public I_Udc, public I_Uac
{
float GetIUac()
{
return r;
}
float GetIUdc()
{
return m;
}
private:
float r = 20;
float m = 20;
};
DataAcq temp;
I_Uac& temp1 = temp;
I_Udc& temp2 = temp;
int main ()
{
volatile float r = temp1.GetIUac();
volatile float m = temp2.GetIUdc();
}
所以问题是我如何强制编译器通过接口引用内联两个函数调用?
据我所知,best/only 保证去虚拟化的方法是首先不进行虚拟化。对您的 classes 稍作改动就可以使用 CRTP 方法,尽管它有点丑陋,尤其是在引用基础 class 类型时,它是完全可行的。
#include <cstdio>
template <typename DerivedT>
class I_Uac {
public:
float GetIUac() {
return static_cast<DerivedT*>(this)->GetIUac();
};
};
template <typename DerivedT>
class I_Udc {
public:
float GetIUdc() {
return static_cast<DerivedT*>(this)->GetIUdc();
};
};
template <template <typename...> class... BaseTs>
class DataAcq final : public BaseTs<DataAcq<BaseTs...>>... {
public:
float GetIUac()
{
std::puts("GetIUac"); // much nicer in compiler explorer output
return r;
}
float GetIUdc()
{
std::puts("GetIUdc");
return m;
}
private:
float r = 20;
float m = 20;
};
DataAcq<I_Udc, I_Uac> temp;
I_Udc<decltype(temp)>& temp1 = temp;
I_Uac<decltype(temp)>& temp2 = temp;
int main ()
{
volatile float r = temp1.GetIUdc();
volatile float m = temp2.GetIUac();
}
我在下面的代码中发现了一个问题:
看起来 GCC 只能去虚拟化第一个接口 I_Udc。接口 GCC 无法将第二个接口去虚拟化 I_Uac。如果我先写 I_Uac,I_Uac 调用将被内联。
这是编译器资源管理器中的代码: https://godbolt.org/z/z6WEoznfW
class I_Uac
{
public:
virtual float GetIUac() = 0;
};
class I_Udc
{
public:
virtual float GetIUdc() = 0;
};
class DataAcq final : public I_Udc, public I_Uac
{
float GetIUac()
{
return r;
}
float GetIUdc()
{
return m;
}
private:
float r = 20;
float m = 20;
};
DataAcq temp;
I_Uac& temp1 = temp;
I_Udc& temp2 = temp;
int main ()
{
volatile float r = temp1.GetIUac();
volatile float m = temp2.GetIUdc();
}
所以问题是我如何强制编译器通过接口引用内联两个函数调用?
据我所知,best/only 保证去虚拟化的方法是首先不进行虚拟化。对您的 classes 稍作改动就可以使用 CRTP 方法,尽管它有点丑陋,尤其是在引用基础 class 类型时,它是完全可行的。
#include <cstdio>
template <typename DerivedT>
class I_Uac {
public:
float GetIUac() {
return static_cast<DerivedT*>(this)->GetIUac();
};
};
template <typename DerivedT>
class I_Udc {
public:
float GetIUdc() {
return static_cast<DerivedT*>(this)->GetIUdc();
};
};
template <template <typename...> class... BaseTs>
class DataAcq final : public BaseTs<DataAcq<BaseTs...>>... {
public:
float GetIUac()
{
std::puts("GetIUac"); // much nicer in compiler explorer output
return r;
}
float GetIUdc()
{
std::puts("GetIUdc");
return m;
}
private:
float r = 20;
float m = 20;
};
DataAcq<I_Udc, I_Uac> temp;
I_Udc<decltype(temp)>& temp1 = temp;
I_Uac<decltype(temp)>& temp2 = temp;
int main ()
{
volatile float r = temp1.GetIUdc();
volatile float m = temp2.GetIUac();
}