簡體   English   中英

變量模板轉換為std :: function <R(ARGS…)> 與GCC合作而不是MSVC2013,為什么?

[英]Variadic Template conversion to std::function<R(ARGS…)> works with GCC and not MSVC2013, why?

如果這是重復,我會道歉。 我在搜索中找不到任何東西。

我可以使用任何最新的功能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;
}

將線路更改為此時,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>          ]

這是解決問題的另一種方法。 如果我對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調用它們的callable時,它們要么丟棄結果,要么將它轉換為R 從傳遞給callable的參數加上返回值的類型,我可以重建(大部分)調用我的std::function的簽名。

此時,我將我的void*轉換為指向該類函數的指針,調用它並返回結果。

如果我永遠不會被拋棄,在破壞點我將我的函數指針轉換為void返回函數,調用它,並完成。


注意事項:

請注意,直接調用FunctionPointer與將示例傳遞給示例中的std::function一樣危險(極端)。

實際上,將函數指針存儲在std::function是過度的。

未在MSVC2015中測試過,但我沒有看到任何在MSVC2015中無效的內容。

如果函數返回voidstd::function某些實現可能無法與上面的函數一起使用。 但是,這將是一個編譯時錯誤。

上面還假設沒有rvalue引用參數的函數,因為在調用時,我無法區分從std::function<void(T)>std::function<void(T&&)> 在這種情況下,我認為它是一個void(T)

這就是我在課外避免一些演員的方法:

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...);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM