我正在使用以下程序:
在main函数中,我想打印poll_timer函数的地址。
该程序使用clang成功编译和运行,但使用GCC则不行。
我在GCC中得到以下错误
"709568706/source.cpp: In function ‘int main()’:
709568706/source.cpp:28:32: error: invalid use of member function ‘static void MessagePoller::poll_timer()’ (did you forget the ‘()’ ?)
std::cout << (void*)m_sut->poll_timer << std::endl;
~~~~~~~^~~~~~~~~~"
#include <iostream>
#include <memory>
class MessagePoller
{
protected:
static void poll_timer()
{
std::cout << "Poll timer Base called\n";
}
};
class TestMessagePoller : public MessagePoller
{
public:
using MessagePoller::poll_timer;
};
typedef std::shared_ptr<TestMessagePoller> TestMessagePollerPtr;
int main()
{
TestMessagePollerPtr m_sut;
m_sut = TestMessagePollerPtr(new TestMessagePoller());
std::cout << "HERE1\n";
m_sut->poll_timer();
std::cout << (void*)m_sut->poll_timer << std::endl;
return 0;
}
我已经尝试了一件事,删除***“using”***语句,并将poll_timer的访问权限更改为public,并且成功了。但我想知道这个项目现在是怎么回事。
2条答案
按热度按时间hjqgdpho1#
是的,这是GCC中的一个bug;我已经提交了https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109958。
这个bug似乎是在4.8分支中首次出现的,所以如果可以的话,你可以考虑降级到4.7.4。
解决方法包括:
&TestMessagePoller::poll_timer
decltype
,即:&std::remove_cvref_t<decltype(*m_sut)>::poll_timer
static void poll_timer() { MessagePoller::poll_timer(); }
代码有效;
&
可以用于类成员访问操作(.
或->
),其中操作数指定静态成员函数(但不是显式对象成员函数)。非静态成员函数在这里被显式排除。polhcujo2#
如果将行改为
gcc将以
即使在gcc v.4.9中也会发生这种情况。我记得它也不接受原始代码,早在4.5版本。Clang会编译。
除了编译器错误之外,这里还有一个形式上的问题。
m_sut->poll_timer
是什么类型的表达式?poll_timer
是一个成员函数,在这种情况下,operator->
是一个等价的m_sut->*std::remove_reference_t<decltype(*m_sut)>::poll_timer
结果类型是可调用的。你只能在上面有意义地使用
operator()
,仅此而已。type::function_name
是一个指向成员函数的指针,它是一个独立于指向成员的指针的类型。因为C++11在静态成员上使用
->
等同于在非静态成员上使用,并且要求类指针正确。其余的是实现定义的,所以gcc不允许获取地址实际上是正确的。允许也不会错。如果m_sut
是一个nullptr
,形式上你得到一个UB。这就是gcc的开发者逻辑的来源,这导致了这个bug。这里所发生的是标准措辞本身的差距。它没有明确禁止或允许这个特定的表达式,但是这样的使用没有意义。主要问题是GCC与此不一致。如果
poll_timer
是public的,并且派生类中没有出现using声明,则代码可以工作。随着形式化声明的出现,派生类的内存模型偏离了标准模型,编译器出现了一些问题。这种不一致性是一个bug。