2016-12-06 8 views
2

メンバー関数のスロットを他のオブジェクトに再バインドする必要があるため(つまり、メンバー関数ポインタと問題のクラスへのポインタを格納する方法が必要でした)、自分自身の「スロット」という別名を呼び出しました。私のスロットクラスは、std :: functionには何が欠けていますか?

私のシステム(64ビットLinux)でstd::functionが2回(GCC/libstdC++)から3回(Clang/libC++)の類似クラスを実装していることを発見しました。サイズは16バイトです。

私はここで実装されていません targetのようなものを理解し
template<typename... ArgTypes> 
class slot 
{ 
public: 
    virtual ~slot() = default; 

    virtual void operator()(const void* object, ArgTypes...) const = 0; 

protected: 
    slot() = default; 
}; 

template<typename Callable, typename... ArgTypes> 
class callable_slot : public slot<ArgTypes...> 
{ 
public: 
    callable_slot(Callable function_pointer_or_lambda) : callable(function_pointer_or_lambda) {} 

    virtual void operator()(const void*, ArgTypes... args) const override { callable(args...); } 

private: 
    Callable callable; 
}; 

template<typename Callable> 
class callable_slot<Callable> : public slot<> 
{ 
public: 
    callable_slot(Callable function_pointer_or_lambda) : callable(function_pointer_or_lambda) {} 

    virtual void operator()(const void*) const override { callable(); } 

private: 
    Callable callable; 
}; 

template<typename Callable, typename... ArgTypes> 
using function_slot = callable_slot<Callable, ArgTypes...>; 

が、私ドン:非メンバ関数とラムダのための実装はこのように書きます(const void*最初の引数はありませんここに示されているメンバ関数のスロットを持つ均一性のためです)欠けている機能のどれかがオブジェクトのサイズを増やすとは思わない。

私が求めているのは、std::functionが私の安価な実装よりもサイズが大きいのはなぜですか?

+3

'のstd :: function'がmake_slotヘルパー機能によって、小さなオブジェクトの最適化 – Brian

答えて

0

クラスの機能は、std::functionとは非常に異なります。クラスのユーザーに、実際のタイプの '呼び出し可能な'オブジェクトをテンプレートの引数として提供するよう要求します。逆に

std::functionは、それが必要なインターフェイスを持つoperator()を持っているとして、これを必要とせず、で任意の呼び出し可能オブジェクトを扱うことができます。タイプが不明なオブジェクト(たとえば、結果がstd::bind)を含むテンプレートを使用してみると、私の意図を知ることができます。

機能が非常に異なるため、サイズの比較は妥当ではありません。

+0

型消去を扱うことができたノー動的割り当て、いいえ? – rubenvb

1

あなたfunction_slotargs...Callableとセットを取り、virtual operator()slot<args...>から継承タイプを返します。

多態的に値として使用するには、スマートポインタでラップしてヒープに格納する必要があります。operator()slot<args...>に転送する必要があります。

std::functionはなく、あなたのslotcallable_slotオブジェクトへを、ラッパーに対応しています。

template<class...Args> 
struct smart_slot { 
    template<class Callable> // add SFINAE tests here TODO! IMPORTANT! 
    smart_slot(Callable other): 
    my_slot(std::make_unique<callable_slot<Callable, Args...>>(std::move(other))) 
    {} 
    void operator()(Args...args) const { 
    return (*my_slot)(std::forward<Args>(args)...); 
    } 
    // etc 
private: 
    std::unique_ptr<slot<Args...>> my_slot; 
}; 

smart_slotはあなたのコードよりもstd::functionに近いです。限り、std::functionは、std::functionのユーザーには見られない実装の詳細です。

ここでは、std::functionが1つのポインタのサイズであることが必要です。 std::functionは、小さいオブジェクトの最適化として知られているものを持っているので、より大きい。

スマートポインタを格納するだけでなく、スマートポインタ自体にメモリブロックがあります。渡したオブジェクトがそのメモリブロックに収まる場合は、ヒープ割り当てを行う代わりにそのブロックをインメモリで構築します。

std::functionは、基本的に、関数ポインタが渡されるような単純なケースでこれを行うことが義務づけられています。品質の高い実装は、より大きくより複雑なオブジェクトのためにそれを行います。MSVCは2つのサイズのオブジェクトに対してこれを行います。std::stringあなたがこれを行う場合

これは意味:

std::function<void(std::ostream&)> hello_world = 
    [s = "hello world"s](std::ostream& os) 
    { 
    os << s; 
    }; 
hello_world(std::cout); 

それん

関連する問題