我有这个功能:
template <typename T, void (T::*pf)()>
void call(T& t)
{
(t.*pf)();
}
如果我的课程foo
包含带有相应签名的方法(例如bar
),我可以像call<foo, &foo::bar>();
一样调用它,这很好。但是,如果bar
为const
,则gcc和msvc很乐意在按此call<const foo, &foo::bar>()
调用时对其进行编译。 Clang抱怨第二个模板参数无效。当我将const
放入模板参数(void (T::*pf)() const
)时,所有树都会编译它。
现在,这不是一个大问题,但如果我不必在模板参数中编写这个可怜的const
,我的代码会变得更加清晰。
所以问题基本上是:标准对此有何看法?这是一个铿锵的bug还是gcc和msvc只是让它滑动因为它们很酷?
PS这是一个完整的复制程序的链接:http://codepad.org/wDBdGvSN
答案 0 :(得分:2)
方法的const
- 属性是其“签名”的一部分。因此,定义和使用指向成员的指针的正确方法是:
R (Obj::*)(Args) // for non-const member
R (Obj::*)(Args) const // for const member
请注意,可以在非const对象上调用const
成员,而R (const Obj::*)(Args)
则不是这样。
解决这个问题的方法是通过定义'call wrappers'来抽象这样的函数指针:
template<typename O, void (O::* f)()>
struct NonConstFunc
{
static void call(O* o)
{
(o->*f)();
}
};
template<typename O, void (O::* f)() const>
struct ConstFunc
{
static void call(O* o)
{
(o->*f)();
}
};
然后,您可以通过以下方式使用它(此处进行抽象):
template<typename Obj, typename Function>
void call(Obj* o)
{
Function::call(o);
}
这只是主要想法。您可以通过自动检测方法是否为const
来扩展它,而无需更改用户代码。