变量模板转换为std :: function <R(ARGS ...)>与GCC而不是MSVC2013一起使用,为什么?

ext*_*spy 22 c++ variadic-templates c++11 c++14

如果这是重复,我会道歉.我在搜索中找不到任何东西.

我可以使用任何最新的功能c ++ 11/c ++ 14.如有必要,我可以升级到VS2015.

我正在尝试编写一个类,它将在分配时自动转换为具有特定签名的std :: function.我有与GCC一起使用的代码,但它在MSVC2013上失败了.代码是重新创建错误的代码段.WTF MSVC?!

另外我知道这是有风险的代码,自动转换函数指针等,但它是私有的插件库实现,我只想定义一次函数签名.

如果有另一种方法可以编写在main()中完成相同功能的代码并且同时适用于这两种方法,那么我就听见了.

GCC c ++ 11工作正常 - 演示

#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;
}
Run Code Online (Sandbox Code Playgroud)

将线路更改为此时,MSVC正常工作...

std::function<void(std::string)> func_hello = f.operator std::function<void(std::string)>();
Run Code Online (Sandbox Code Playgroud)

当我有这个时,MSVC失败并出现同样的错误......

std::function<void(std::string)> func_hello = (std::function<void(std::string)>)f;
Run Code Online (Sandbox Code Playgroud)

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>          ]
Run Code Online (Sandbox Code Playgroud)

Yak*_*ont 1

这是解决您的问题的不同方法。如果我对 MSVC 2015 功能的理解是正确的,那么它应该可以在那里工作。

(我假设您的问题是想要相对透明地将void*未知函数的 a 转换为std::function具有未知函数实际具有的签名的 a ,而不必重复该函数的签名。)

我不是在我们被转换为 的点处转换 void 指针std::function,而是在调用函数并通过“返回类型推导”计算返回值时(或者,当没有计算返回值时)进行转换诡计:

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 };
  }
};
Run Code Online (Sandbox Code Playgroud)

活生生的例子

std::function调用它们的可调用对象时,它们要么丢弃结果,要么将其转换为R. 根据传递给可调用对象的参数,加上返回值转换为的类型,我可以重建(大部分)std::function调用我的签名。

此时,我将 my 转换void*为指向此类函数的指针,调用它并返回结果。

如果我从未被强制转换为某个东西,那么在销毁时我会将函数指针强制转换为void返回函数,调用它,然后就完成了。


注意事项:

请注意,直接调用与将其传递给示例中的FunctionPointera 一样危险(非常危险)。std::function

确实,将函数指针存储在 a 中std::function是多余的。

未在 MSVC2015 中进行测试,但我没有看到任何在 MSVC2015 中不起作用的内容。

如果您的函数返回 ,则 的某些实现可能std::function无法与上述一起工作void。然而,这将是一个编译时错误。

上面还假设不存在带有右值引用参数的函数,因为在调用时,我无法区分是从 a 调用std::function<void(T)>还是从 a调用std::function<void(T&&)>。我认为在这种情况下是这样void(T)