C++:具有可变模板的成员函数指针参数
C++: Member function pointer parameter with variadic template
我正在为我正在进行的项目编写一个简短的单元测试程序。
如果给定函数抛出某种异常,则此测试通过:
template <class Exception, class Return, class... Args>
bool throws(std::string s, Return(*fn)(Args...), Args... args)
{
try
{
fn(args...);
}
catch (Exception& e)
{
return output(s, true);
}
catch (...)
{
return output(s, false);
}
return output(s, false);
}
使用它看起来像这样:
throws<int>("Testing: Throws int", &foo);
这很管用。但现在我正在尝试编写一个类似的函数,它将与类的成员函数一起使用。
到目前为止,我得到的是:
template <class Exception, class Object, class Return, class... Args>
bool throws(std::string s, Object& o, Return(Object::*fn)(Args...), Args... args)
{
// ...
(o.*fn)(args...);
// ...
}
template <class Exception, class Object, class Return, class... Args>
bool throws(std::string s, const Object& o, Return(Object::*fn)(Args...) const, Args... args)
{ /* ... */ }
使用时应该是这样的:
Bar<int> b1(5), b2(2);
typedef Bar<int>& (Bar<int>::*fn)(const Bar<int>&);
typedef Bar<int> (Bar<int>::*const_fn)(const Bar<int>&) const;
fn foo = &Bar<int>::foo;
const_fn const_foo = &Bar<int>::const_foo;
throws<int>("Testing member function", b1, foo, b2);
throws<int>("Testing const member function", b1, const_foo, b2);
但当我这样做时,我会得到这两个throws((函数的"无匹配函数调用"。具体而言:
error: no matching function for call to ‘throws(const char [30], Bar<int>&, Bar<int> (Bar<int>::*&)(const Bar<int>&)const, const Bar<int>&)
非常量版本也有类似的版本。
我注意到一些const是不同的,所以我尝试在使用函数的地方放入一些const_cast,但没有骰子。这是我第一次使用成员函数指针和可变模板(根本不用说同时使用了(,所以我肯定会错过一些东西。。。有比我更有经验的人有什么想法吗?
我唯一无法解释的是(Bar<int>::*&)
。&最后与呼叫不匹配。。。但这应该不是问题吧?
编辑:根据要求,我的酒吧类别:
template <class T>
class Bar
{
private:
T _data;
public:
Bar (const int i) : _data(i) {}
Bar const_foo (const Bar& other) const
{
if (_data != other._data)
{
throw _data;
}
return Bar(_data);
}
Bar& foo (const Bar& other)
{
if (_data != other._data)
{
throw _data;
}
return *this;
}
};
以及全部错误:
test.cpp: In function ‘int main()’:
test.cpp:111:53: error: no matching function for call to ‘throws(const char [24], Bar<int>&, Bar<int>& (Bar<int>::*&)(const Bar<int>&), Bar<int>&)’
test.cpp:111:53: note: candidates are:
test.cpp:31:6: note: template<class Exception, class Return, class ... Args> bool throws(std::string, Return (*)(Args ...), Args ...)
test.cpp:53:6: note: template<class Exception, class Object, class Return, class ... Args> bool throws(std::string, Object&, Return (Object::*)(Args ...), Args ...)
test.cpp:75:6: note: template<class Exception, class Object, class Return, class ... Args> bool throws(std::string, const Object&, Return (Object::*)(Args ...)const, Args ...)
test.cpp:112:65: error: no matching function for call to ‘throws(const char [30], Bar<int>&, Bar<int> (Bar<int>::*&)(const Bar<int>&)const, Bar<int>&)’
test.cpp:112:65: note: candidates are:
test.cpp:31:6: note: template<class Exception, class Return, class ... Args> bool throws(std::string, Return (*)(Args ...), Args ...)
test.cpp:53:6: note: template<class Exception, class Object, class Return, class ... Args> bool throws(std::string, Object&, Return (Object::*)(Args ...), Args ...)
test.cpp:75:6: note: template<class Exception, class Object, class Return, class ... Args> bool throws(std::string, const Object&, Return (Object::*)(Args ...)const, Args ...)
我注意到您使用的是非成员版本,该版本的函数不带任何参数。我相信当你试图传递参数时,你的代码会失败,而不是当你把它改为使用成员函数时。通过将其更改为采用成员函数并在同一步骤中传递参数,您混淆了失败的真正原因。我相信,如果您尝试使用零参数的成员函数,您的代码会起作用。我相信,如果你试图将非成员版本与接受一个或多个参数的函数一起使用,它会失败。
template <class Exception, class Object, class Return, class... Args>
bool throws(std::string s, Object& o, Return(Object::*fn)(Args...), Args... args)
在这里,您告诉编译器throws
的第四个参数和函数指针的第一个参数的类型必须完全相同。
error: no matching function for call to ‘throws(const char [24], Bar<int>&,
Bar<int>& (Bar<int>::*&)(const Bar<int>&), Bar<int>&)’
编译器告诉您,throws
的第四个参数和函数指针的第一个参数不同,因此找不到匹配的throws
声明。您的模板无法匹配,因为这意味着Args...
必须同时推断为const Bar<int>&
和Bar<int>&
,而这是两种不同的类型。
@WhozCraig在评论中提供的解决方案之所以有效,是因为函数类型和参数类型是独立推导的。他的解决方案通过通用引用传递函数指针,但这是偶然的;它也可以通过const
左值引用或通过值获取函数指针。
template <class Exception, class Func, class... Args>
bool throws(std::string s, Func fn, Args&&... args)
{ /*...*/ }
template <class Exception, class Object, class MemFunc, class... Args>
bool throws(std::string s, Object& o, MemFunc fn, Args&&... args)
{ /*...*/ }
不幸的是,使用这种方法,您可能会遇到过载不明确的情况。对此,简单的解决方案是将成员版本重命名为memberThrows
。更复杂的版本是使用标记调度或SFINAE(在这种情况下,我更喜欢前者(。
template <class Exception, class Func, class... Args>
bool throwsHelper(std::false_type, std::string s, Func fn, Args&&... args)
{ /*...*/ }
template <class Exception, class MemFunc, class Object, class... Args>
bool throwsHelper(std::true_type, std::string s, MemFunc fn, Object&& o, Args&&... args)
{ /*...*/ }
template <class Exception, class Func, class... Args>
bool throws(std::string s, Func fn, Args&&... args)
{
using isMember = typename std::is_member_pointer<Func>::type;
return throwsHelper(isMember(), s, fn, std::forward<Args>(args)...);
}
请注意,我必须将参数的顺序更改为成员版本,以便在这两种情况下都允许统一调用。
确保Bar<int>::const_foo
是const
成员函数,并且它具有返回类型Bar<int>
(而不是引用(。如果这不是问题所在,请发布更多代码。
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 将公共但非静态的成员函数与ALGLIB集成
- 使用指向成员的指针将成员函数作为参数传递
- 将重载的成员函数传递给函数模板
- 我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
- 如何在C++中使用非静态成员函数作为回调函数
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 关联容器的下界复杂性:成员函数与非成员函数
- 在 C++ 中用派生类型重写成员函数
- 链表的泛型函数remove()与成员函数remove)
- 如何将lambda作为模板类的成员函数参数
- constexpr构造函数需要常量成员函数时出现问题
- 将自由函数绑定为类成员函数
- 区分非成员函数和头文件中的成员函数
- 如何从子成员函数修改父公共成员变量
- 保留对其他类的成员函数的引用
- 在运算符重载定义中使用成员函数(const错误)
- 内联如何影响模块接口中的成员函数
- 将成员函数指针作为参数传递给模板方法