如果这是重复,我会道歉。我在搜索中找不到任何东西。
我可以使用任何最新的功能c ++ 11 / c ++ 14。如有必要,我可以升级到VS2015。
我试图编写一个类,它会在分配时自动转换为具有特定签名的std :: function。我有与GCC一起使用的代码,但它在MSVC2013上失败了。代码是重新创建错误的代码段。 WTF MSVC?!
此外,我知道这是有风险的代码,自动转换函数指针等,但它是私有实现插件库的,我只想定义一次函数签名。
如果还有另一种方法可以编写在main()中完成相同功能的代码,并且同时适用于这两种方法,那我就是全部。
GCC c ++ 11工作正常 - Demo
#include <functional>
#include <string>
#include <iostream>
class FunctionPointer
{
void* fp;
public:
FunctionPointer(void* ptr)
: fp(ptr)
{}
// Overload casting operator to
// a certain function signiture
template<class R, class... ARGS>
operator std::function<R(ARGS...)>(){
typedef R(*func_ptr)(ARGS...);
return std::function<R(ARGS...)>((func_ptr)fp);
}
};
void hello(std::string msg){
std::cout << "Hello " << msg << std::endl;
}
int main() {
FunctionPointer f((void*)hello);
std::function<void(std::string)> func_hello = f;
func_hello("World!");
return 0;
}
当我将线路更改为此时,MSVC正常工作......
std::function<void(std::string)> func_hello = f.operator std::function<void(std::string)>();
当我有这个时,MSVC失败并出现同样的错误......
std::function<void(std::string)> func_hello = (std::function<void(std::string)>)f;
MSVC在一个难以阅读的文件中失败并出现以下错误。它似乎是推断出错误的函数签名。
xrefwrap.h:283 - error C2064: term does not evaluate to a function taking 1 arguments
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xrefwrap(283): error C2064: term does not evaluate to a function taking 1 arguments
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(228) : see reference to function template instantiation '_Ret std::_Callable_obj<FunctionPointer,false>::_ApplyX<_Rx,_Ty>(_Ty &&)' being compiled
1> with
1> [
1> _Ret=void
1> , _Rx=void
1> , _Ty=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(228) : see reference to function template instantiation '_Ret std::_Callable_obj<FunctionPointer,false>::_ApplyX<_Rx,_Ty>(_Ty &&)' being compiled
1> with
1> [
1> _Ret=void
1> , _Rx=void
1> , _Ty=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(226) : while compiling class template member function 'void std::_Func_impl<_MyWrapper,_Alloc,_Ret,std::string>::_Do_call(std::string &&)'
1> with
1> [
1> _Alloc=std::allocator<std::_Func_class<void,std::string>>
1> , _Ret=void
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(495) : see reference to class template instantiation 'std::_Func_impl<_MyWrapper,_Alloc,_Ret,std::string>' being compiled
1> with
1> [
1> _Alloc=std::allocator<std::_Func_class<void,std::string>>
1> , _Ret=void
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(396) : see reference to function template instantiation 'void std::_Func_class<_Ret,std::string>::_Do_alloc<_Myimpl,FunctionPointer&,_Alloc>(_Fty,_Alloc)' being compiled
1> with
1> [
1> _Ret=void
1> , _Alloc=std::allocator<std::_Func_class<void,std::string>>
1> , _Fty=FunctionPointer &
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(396) : see reference to function template instantiation 'void std::_Func_class<_Ret,std::string>::_Do_alloc<_Myimpl,FunctionPointer&,_Alloc>(_Fty,_Alloc)' being compiled
1> with
1> [
1> _Ret=void
1> , _Alloc=std::allocator<std::_Func_class<void,std::string>>
1> , _Fty=FunctionPointer &
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(385) : see reference to function template instantiation 'void std::_Func_class<_Ret,std::string>::_Reset_alloc<FunctionPointer&,std::allocator<std::_Func_class<_Ret,std::string>>>(_Fty,_Alloc)' being compiled
1> with
1> [
1> _Ret=void
1> , _Fty=FunctionPointer &
1> , _Alloc=std::allocator<std::_Func_class<void,std::string>>
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(385) : see reference to function template instantiation 'void std::_Func_class<_Ret,std::string>::_Reset_alloc<FunctionPointer&,std::allocator<std::_Func_class<_Ret,std::string>>>(_Fty,_Alloc)' being compiled
1> with
1> [
1> _Ret=void
1> , _Fty=FunctionPointer &
1> , _Alloc=std::allocator<std::_Func_class<void,std::string>>
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,std::string>::_Reset<FunctionPointer&>(_Fty)' being compiled
1> with
1> [
1> _Ret=void
1> , _Fty=FunctionPointer &
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,std::string>::_Reset<FunctionPointer&>(_Fty)' being compiled
1> with
1> [
1> _Ret=void
1> , _Fty=FunctionPointer &
1> ]
1> c:\users\cameron\desktop\desktop\programming\projects\c++ projects\garbage\templatetest\main.cpp(32) : see reference to function template instantiation 'std::function<void (std::string)>::function<FunctionPointer&>(_Fx)' being compiled
1> with
1> [
1> _Fx=FunctionPointer &
1> ]
1> c:\users\cameron\desktop\desktop\programming\projects\c++ projects\garbage\templatetest\main.cpp(32) : see reference to function template instantiation 'std::function<void (std::string)>::function<FunctionPointer&>(_Fx)' being compiled
1> with
1> [
1> _Fx=FunctionPointer &
1> ]
答案 0 :(得分:1)
这是解决问题的另一种方法。如果我对MSVC 2015的功能的理解是正确的,它应该在那里工作。
(我假设您的问题是希望相对透明地将void*
转换为未知函数到具有未知函数实际具有的签名的std::function
,而不必重复该函数的签名。 )
而不是在我们被转换为std::function
的点处转换void指针,而是在调用函数并计算返回值的时候执行它(或者,当没有计算返回值时)通过“返回类型扣除”技巧:
template<class...Args>
struct void_ptr_deferred_execution_t {
std::tuple<Args&&...> args;
void const* pf = nullptr;
void_ptr_deferred_execution_t( std::tuple<Args&&...> a, void const* p ):
args(std::move(a)),
pf(p)
{}
template<class R, size_t...Is>
R invoke( std::index_sequence<Is...> ){
using f_t = R(*)(Args...);
f_t f = f_t(pf);
pf = nullptr;
return f(std::forward<Args>(std::get<Is>(args))...);
}
template<class R>
operator R()&&{
return invoke<R>( std::index_sequence_for<Args...>{} );
}
~void_ptr_deferred_execution_t() {
if (pf) invoke<void>(std::index_sequence_for<Args...>{});
}
};
class FunctionPointer
{
void* fp;
public:
FunctionPointer(void* ptr)
: fp(ptr)
{}
template<class...Args>
void_ptr_deferred_execution_t<Args...>
operator()(Args&&...args)const {
return { std::forward_as_tuple(std::forward<Args>(args)...), fp };
}
};
当std::function
调用他们的可调用对象时,他们要么丢弃结果,要么将其转换为R
。从传递给callable的参数加上返回值的类型,我可以重建(大部分)调用我的std::function
的签名。
此时,我将void*
转换为指向该类函数的指针,调用它并返回结果。
如果我从未被某些东西抛弃,那么在破坏点我将我的函数指针转换为void
返回函数,调用它,并完成。
注意事项:
请注意,直接调用FunctionPointer
与将示例传递给std::function
一样危险(非常)。
实际上,将函数指针存储在std::function
中是过度的。
未在MSVC2015中测试过,但我没有看到任何在MSVC2015中无效的内容。
如果您的函数返回std::function
,则void
的某些实现可能无法使用上述内容。但是,这将是一个编译时错误。
上面还假设没有rvalue引用参数的函数,因为在调用时,我无法区分从std::function<void(T)>
和std::function<void(T&&)>
被调用。我认为在这种情况下它是void(T)
。
答案 1 :(得分:1)
这就是我在课外避免一些演员的方法:
class FunctionPointer
{
void* fp;
public:
FunctionPointer() = default;
template<class Ret, class Fn, class... Args> void assign_fn(Fn fn, Args... args)
{
std::function<Ret(Args...)> *f = new std::function<Ret(Args...)>;
*f = Fn; // Tip: you can use enable_if combined with is_assignable to make sure this can be done.
// Both are regular pointers, so conversion shouldn't be a problem.
fp = reinterpret_cast<void*>(f);
}
// Overload casting operator to
// a certain function signature
template<class R, class... ARGS>
operator std::function<R(ARGS...)>(){
typedef R(*func_ptr)(ARGS...);
return std::function<R(ARGS...)>((func_ptr)fp);
}
};
此外,您可以利用std :: function可以指向任何可调用对象这一事实,方法是使您的函数指针可调用(添加一个operator()),这将非常相似转换为std :: function。
template<class Ret, class... Args> Ret operator()(Args... args)
{
std::function<Ret(Args...)> f = *(reinterpret_cast<std::function<Ret(Args...)>*>(fp));
return f(args...);
}