16

std::functionと組み合わせて使用​​しようとしていますstd::bindが、問題が発生しています。

これは機能します:

#include <functional>
#include <iostream>

void print() {
    std::cout << 2;
}

int main() {
    std::function<void ()> foo = print;
    (*foo.target<void (*)()>())(); //prints 3
}

これは、次の2行目でクラッシュしmainます。

#include <functional>
#include <iostream>

void print (int i) {
    std::cout << i;
}

int main() {
    std::function<void ()> foo = std::bind (print, 2);
    (*foo.target<void (*)()>())();
}

私は本当にを保持していてstd::function<void ()>、関数を返すことができる必要があります。ただそれを呼ぶだけではありません。使用法は次のようになると思います。

#include <functional>
#include <iostream>

void print (int i) {
    std::cout << i;
}

int main() {
    Container c (std::bind (print, 2));

    //I would expect the original
    c.func() (3); //prints 3

    if (c.func() == print) /* this is what I'm mostly getting at */
}

元の関数を取得してそれを返す方法、または別の方法はありますか?void (*)()バインドされた署名と非常によく一致するため、returnタイプとも競合します。

4

4 に答える 4

30

これはまったく不可能です。存在する全体的な理由は、関数ポインターは恐ろしく吸い込まれ、地獄Cの相互運用の燃焼基準をstd::function持っている運命の魂を除いて、誰もが二度と使用してはならないということです。

std::function<void()>一般的な場合、Aをに変換することはできませんvoid(*)()。これが最初の例で機能する唯一の理由は、元々はたまたまであるためです。void(*)()

于 2012-06-07T19:46:55.613 に答える
16

これは、小さなテンプレートメタプログラミングを使用して実現できます。私は最近、OpenGL GLUT(コールバック関数ポインターに依存)の周りにジェネリックC++ラッパーを書いているときにこれを使用しました。アプローチ:

  1. シングルトンテンプレートタイプのインスタンスをインスタンス化します。
  2. std::functionをシングルトンインスタンスのメンバーとして保存します
  3. 静的メンバー関数を介してstd::関数を呼び出します(静的メンバー関数とフリー関数は同じタイプであるため、「invoke」関数はフリー関数ポインターとして使用できます)

GCC4.8でC++11でテストされています。

#include <unistd.h>
#include <thread>
#include <chrono>
#include <mutex>
#include <functional>
#include <iostream>
#include <cmath>

template <const size_t _UniqueId, typename _Res, typename... _ArgTypes>
struct fun_ptr_helper
{
public:
    typedef std::function<_Res(_ArgTypes...)> function_type;

    static void bind(function_type&& f)
    { instance().fn_.swap(f); }

    static void bind(const function_type& f)
    { instance().fn_=f; }

    static _Res invoke(_ArgTypes... args)
    { return instance().fn_(args...); }

    typedef decltype(&fun_ptr_helper::invoke) pointer_type;
    static pointer_type ptr()
    { return &invoke; }

private:
    static fun_ptr_helper& instance()
    {
        static fun_ptr_helper inst_;
        return inst_;
    }

    fun_ptr_helper() {}

    function_type fn_;
};

template <const size_t _UniqueId, typename _Res, typename... _ArgTypes>
typename fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::pointer_type
get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f)
{
    fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::bind(f);
    return fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::ptr();
}

template<typename T>
std::function<typename std::enable_if<std::is_function<T>::value, T>::type>
make_function(T *t)
{
    return {t};
}

int main()
{
    std::cout << (void*)get_fn_ptr<0>(make_function(::sin))<<std::endl;
    return 0;
}
于 2013-08-24T20:35:10.693 に答える
6

関数ポインタがない場合もあるため、関数ポインタをから取得することはできませんstd::function。代わりに、メンバー関数ポインター、またはを実装するオブジェクトである可能性がありますoperator()

于 2012-06-07T19:46:14.127 に答える
1

これは一般的には不可能ですが、ほとんどのC APIには、C関数ポインターと一緒に渡すことができる「コンテキスト」ポインターがあります。したがって、相互運用の場合は、次のようにラップできます(APIが最初にこの「コンテキスト」パラメーターを渡すことを前提としています)。

template <class R, class... Args>
struct CFunctionPointer
{
    std::function<R(Args...)> func;

    static R callback(void* context, Args... args)
    {
        const CFunctionPointer* unpackedThis = reinterpret_cast<const CFunctionPointer*>(context);
        return unpackedThis->func(std::forward<Args>(args)...);
    }
};

これは次のように呼ばれます:

auto callable = CFunctionPointer<void, const uint8_t*, const uint8_t*>{ [](const uint8_t* begin, const uint8_t* end) { std::cout << "Hello world\n"; } };
cfunc(..., &callable, &callable.callback);

悲しいことに、引数の型を2回複製します。

于 2021-01-21T10:36:45.547 に答える