使用函数指针的类型擦除不适用于 GCC
Type erasure with function pointers does not work with GCC
我正在尝试使用一些函数指针和模板进行类型擦除,如下例所示。我觉得奇怪的是 GCC 我得到了错误的结果,而与 VS 2017 一样,我得到了预期的结果。那么,谁对谁错,为什么?
COLIRU 上的实例:http://coliru.stacked-crooked.com/a/225db5711c07c8b0
struct A { void PrintA() { std::cout << "Event A" << std::endl; } };
struct B { void PrintB() { std::cout << "Event B" << std::endl; } };
struct C { void PrintC() { std::cout << "Event C" << std::endl; } };
struct RunBase
{
virtual void operator()() = 0;
};
template <typename T>
struct Run : public RunBase
{
using FUNC = void (T::*)();
Run(T& o, FUNC&& f) : mObj(o), mFunc(f) {}
void operator()() override { (mObj.*mFunc)(); }
T& mObj;
FUNC& mFunc;
};
int main()
{
A a;
B b;
C c;
std::vector<std::unique_ptr<RunBase> > mFuncs;
mFuncs.push_back(std::make_unique<Run<A> >(a, &A::PrintA));
mFuncs.push_back(std::make_unique<Run<B> >(b, &B::PrintB));
mFuncs.push_back(std::make_unique<Run<C> >(c, &C::PrintC));
for (auto& i : mFuncs)
(*i)();
return 0;
}
预期结果:
Event A
Event B
Event C
但是 GCC 给了我:
Event C
Event C
Event C
这是因为你在你的对象中存储了一个引用,但是 &A::PrintA
等是临时对象,在完整表达式的末尾被销毁,所以成员引用是悬空的,它的使用导致未定义的行为。
简单的存储一份成员函数指针来修复它:
FUNC mFunc;
PS。当 mFuncs
被销毁时,唯一指针通过基指针删除子对象。除非您声明 RunBase::~RunBase
virtual.
,否则行为未定义
So, who is correct and who is wrong and why ?
你的程序有误;没有正确的行为。
我正在尝试使用一些函数指针和模板进行类型擦除,如下例所示。我觉得奇怪的是 GCC 我得到了错误的结果,而与 VS 2017 一样,我得到了预期的结果。那么,谁对谁错,为什么?
COLIRU 上的实例:http://coliru.stacked-crooked.com/a/225db5711c07c8b0
struct A { void PrintA() { std::cout << "Event A" << std::endl; } };
struct B { void PrintB() { std::cout << "Event B" << std::endl; } };
struct C { void PrintC() { std::cout << "Event C" << std::endl; } };
struct RunBase
{
virtual void operator()() = 0;
};
template <typename T>
struct Run : public RunBase
{
using FUNC = void (T::*)();
Run(T& o, FUNC&& f) : mObj(o), mFunc(f) {}
void operator()() override { (mObj.*mFunc)(); }
T& mObj;
FUNC& mFunc;
};
int main()
{
A a;
B b;
C c;
std::vector<std::unique_ptr<RunBase> > mFuncs;
mFuncs.push_back(std::make_unique<Run<A> >(a, &A::PrintA));
mFuncs.push_back(std::make_unique<Run<B> >(b, &B::PrintB));
mFuncs.push_back(std::make_unique<Run<C> >(c, &C::PrintC));
for (auto& i : mFuncs)
(*i)();
return 0;
}
预期结果:
Event A
Event B
Event C
但是 GCC 给了我:
Event C
Event C
Event C
这是因为你在你的对象中存储了一个引用,但是 &A::PrintA
等是临时对象,在完整表达式的末尾被销毁,所以成员引用是悬空的,它的使用导致未定义的行为。
简单的存储一份成员函数指针来修复它:
FUNC mFunc;
PS。当 mFuncs
被销毁时,唯一指针通过基指针删除子对象。除非您声明 RunBase::~RunBase
virtual.
So, who is correct and who is wrong and why ?
你的程序有误;没有正确的行为。