我需要调用一个需要函数指针的方法,但我真正想传递给它的是一个仿函数.这是我正在尝试做的一个例子:
#include <iostream>
#include "boost/function.hpp"
typedef int (*myAdder)(int);
int adderFunction(int y) { return(2 + y); }
class adderClass {
public:
adderClass(int x) : _x(x) {}
int operator() (int y) { return(_x + y); }
private:
int _x;
};
void printer(myAdder h, int y) {
std::cout << h(y) << std::endl;
}
int main() {
myAdder f = adderFunction;
adderClass *ac = new adderClass(2);
boost::function1<int, int> g =
std::bind1st(std::mem_fun(&adderClass::operator()), ac);
std::cout << f(1) << std::endl;
std::cout << g(2) << std::endl;
printer(f, 3); …Run Code Online (Sandbox Code Playgroud) 以下代码尝试根据成员函数指针类型的返回类型来专门化类模板'special',导致VC9编译错误:
template<class F> struct special {};
template<class C> struct special<void(C::*)()> {};
template<class R, class C> struct special<R(C::*)()> {};
struct s {};
int main()
{
special<void(s::*)()> instance;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
错误C2752:'special':多个部分特化匹配模板参数列表
GCC-4.3.4接受相同的代码,如下所示:http ://ideone.com/ekWGg
这是VC9中的一个错误,如果是这样,这个错误是否仍然存在于VC10中?
然而,我提出了一个可怕的侵入式解决方法(对于这个特定的用例,至少.欢迎更一般的解决方案):
#include <boost/function_types/result_type.hpp>
#include <boost/type_traits/is_same.hpp>
template<typename F, typename R>
struct is_result_same :
boost::is_same<
typename boost::function_types::result_type<F>::type,
R
>
{};
template<class F, bool = is_result_same<F, void>::value>
struct special {};
template<class R, class C> struct special<R(C::*)(), true> {};
template<class R, class C> struct special<R(C::*)(), false> {};
Run Code Online (Sandbox Code Playgroud) c++ templates member-function-pointers partial-specialization visual-c++
我正在尝试向我的项目添加一个简单的消息传递系统,其中事件可以由函数调用,这将导致注册到该事件的所有回调被调用.
现在,执行此操作的逻辑方法是使用函数指针.可以很容易地将指针传递给事件管理器所需的回调函数,以进行注册.事件回调函数总是返回一个int并void*作为参数.
但是我不想将静态全局函数注册为我的事件回调 - 我想用类成员函数来做.
是否有可能用C++实现这一目标?存储和调用指向不同类的成员函数但具有相同函数头的指针.
如果这是不可能的,你对我如何解决这个问题有什么建议吗?我真的想直接向我的类添加事件监听器.
在我的代码中,我有一个类,它注册其他类的方法:
#include <iostream>
using namespace std;
template< typename C>
class Reg {
public:
template< typename R, typename A>
void register_f( string name, R ( C:: *method_p ) ( A)) { /*registration process*/ }
// template< typename R>
// void register_void_f( string name, R ( C:: *method_p ) ( void)) { /*registration process*/ }
};
class A {
public:
int f( void) { return 1; }
void g( int x) { /* some code*/ }
};
int main() {
Reg< A> …Run Code Online (Sandbox Code Playgroud) 我试图声明一个变量,使其类型与我有成员函数指针的成员函数的返回类型相同.
class Widget {
public:
std::chrono::milliseconds Foo();
};
Run Code Online (Sandbox Code Playgroud)
例如,给定一个成员函数的指针fn,它指向Widget::Foo的,我怎么会声明一个变量blah,使得它得到Widget::Foo的返回类型(std::chrono::milliseconds)?
我发现从使用博客中的一些有前途的指导result_of,从<type_traits>沿decltype,但我似乎无法得到它的工作.
auto fn = &Widget::Foo;
Widget w;
std::result_of<decltype((w.*fn)())>::type blah;
Run Code Online (Sandbox Code Playgroud)
这种方法对我有意义,但VC++ 2013不喜欢它.
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xrefwrap(58): error C2064: term does not evaluate to a function taking 0 arguments
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xrefwrap(118) : see reference to class template instantiation 'std::_Result_of<_Fty,>' being compiled
with
[
_Fty=std::chrono::milliseconds (__cdecl Widget::* )(void)
]
scratch.cpp(24) : see …Run Code Online (Sandbox Code Playgroud) 从
将成员函数指针传递给模板函数的重载类方法产生了这个问题.
你不需要阅读它来理解这个问题.可能两个问题都有相同的答案.
#include<set>
template<typename Return, typename T>
T ReceiveFuncPtr (Return (T::*Method)(const int&))
{
T obj; // Found and declared an object of actual container class
(obj.*Method)(1); // Some processing
return obj; // Returned that container class object with RVO
}
int main ()
{
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
}
Run Code Online (Sandbox Code Playgroud)
错误很有趣:
In function 'int main()':
error: no matching function for call to 'ReceiveFuncPtr(<unresolved overloaded function type>)'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: candidate is:
note: template<class Return, …Run Code Online (Sandbox Code Playgroud) c++ templates member-function-pointers standard-library c++11
考虑这个template函数,调用一个对象的方法class T.
template<class T, void (T::*Method)()>
void circuitousInvoke(T* callee) {
(callee->*Method)();
}
Run Code Online (Sandbox Code Playgroud)
例:
struct A {
void test() {};
}
circuitousInvoke<A, &A::test>(new A);
Run Code Online (Sandbox Code Playgroud)
由于参数中的circuitousInvoke已经知道类型T callee,有没有办法避免输入这种类型?
circuitousInvoke<&A::test>(new A);
Run Code Online (Sandbox Code Playgroud)
此问题仅涉及模板功能.在这种情况下,继承和其他基于类的解决方案不适用.(在我的项目中使用包装器对象会比输入其他名称更糟糕.)
假设我有以下两个类:
template<typename T>
struct Base
{
void foo();
};
struct Derived : Base<Derived> {};
Run Code Online (Sandbox Code Playgroud)
我可以做这个:
void (Derived::*thing)() = &Derived::foo;
Run Code Online (Sandbox Code Playgroud)
编译器很高兴(正如我所料).
当我把它放在两个级别的模板中时突然爆炸:
template<typename T, T thing>
struct bar {};
template<typename T>
void foo()
{
bar<void (T::*)(),&T::foo>{};
}
int main()
{
foo<Derived>(); // ERROR
foo<Base<Derived>>(); // Works fine
}
Run Code Online (Sandbox Code Playgroud)
这失败了:
non-type template argument of type 'void (Base<Derived>::*)()' cannot be converted to a value of type 'void (Derived::*)()'
Run Code Online (Sandbox Code Playgroud)
为什么简单的案例工作而更复杂的案例失败了?我相信这与这个问题有关,但我并不完全确定......
成员函数指针不能是reinterpret_cast函数指针。(不过,GCC需要该-pedantic-errors标志来强制执行该操作。)
但是,GCC,Clang和MSVC似乎同意将成员函数指针转换为对函数指针的引用是可以的。请参见以下示例:
#include<type_traits>
struct A {
void f() {}
};
int main() {
auto x = &A::f;
auto y = reinterpret_cast<void(*&)()>(x);
// auto y = reinterpret_cast<void(*)()>(x);
static_assert(std::is_same_v<decltype(y), void(*)()>);
}
Run Code Online (Sandbox Code Playgroud)
该程序可以在所有三个编译器上编译,但是当使用注释掉的行而不是前一个注释行时,所有程序(带有pedantic标志)都无法编译。
我在标准中看不到任何允许这种转换的规则。程序格式错误,编译器无法对其进行诊断还是程序格式正确?
如果是后者,那么确切的转换顺序是什么,标准在哪里允许它,并且可以将函数指针转换回原始类型以便调用它,还是使用引用来初始化y已经不确定的行为?
c++ member-function-pointers function-pointers language-lawyer reinterpret-cast
所以我有这样一个场景,我想调用一个类的任何一个函数,其中有问题的函数具有相同的原型,但它也被重载了。因为我知道指向成员的指针,所以我的直接反应是这样的:
struct test
{
int overloaded(char) {}
int overloaded(int) {}
int overloadedone(char) {}
int overloadedone(int) {}
} test;
int main()
{
(test.*(true ? (&test::overloaded) : (&test::overloadedone)))(1);
}
Run Code Online (Sandbox Code Playgroud)
然而事实证明编译器(MSVC - 2019 Preview 最新版本与 std C++ 预览版)无法推断类型,我必须写:
(test.*(true ? static_cast<int (test::*)(int)>(&test::overloaded) : static_cast<int (test::*)(int)>(&test::overloadedone)))(1);
Run Code Online (Sandbox Code Playgroud)
相反,这让我回到了过去:
true ? test.overloaded(1) : test.overloadedone(1);
Run Code Online (Sandbox Code Playgroud)
但我想知道这是否是要求这些演员的定义行为。甚至:
(test.*static_cast<int (test::*)(int)>(true ? (&test::overloaded) : (&test::overloadedone)))(1);
Run Code Online (Sandbox Code Playgroud)
不起作用。
您必须像第二个示例中那样针对三元的两种可能性中的每一种编写上述转换。