2016-12-24 22 views
4

スタティック(コンパイル時に)関数のリファレンスをテンプレート引数として埋め込み、参照された関数への転送呼び出しとしてoperator()を実装する標準のC++ 14タイプのテンプレートを探しています。標準の静的関数ラッパー型テンプレートはありますか?

私は、std::functionが存在することを知っていますが、データメンバーとして関数ポインタを格納しています。ラッパーの型がemptydefault-constructibleになるように、関数の参照を型シグネチャに埋め込むようにします。

私は(例えば、ユースケース付き)作業の実装を持っている:

#include <cstring> 
#include <iostream> 
#include <memory> 

// Implementation: 

template <typename Ret, typename... Args> 
struct fn_t { 
    template <Ret (Func)(Args...)> 
    struct fn_ref { 
     Ret operator() (Args &&...args) const { 
      return Func(std::forward<Args>(args)...); 
     } 
    }; 
}; 

// Example use case: 

template <typename T> 
using unique_c_ptr = std::unique_ptr<T, fn_t<void, void *>::fn_ref<std::free>>; 

int main() { 
    // { char *, void (*)(void *) } (16 bytes) 
    std::unique_ptr<char[], decltype(&std::free)> ptr1(::strdup("Hello"), &std::free); 

    // { char *, fn_t<void, void *>::fn_ref<std::free> } (8 bytes) 
    unique_c_ptr<char[]> ptr2(::strdup("Hello")); 

    std::cout << sizeof ptr1 << '\n'  // 16 
       << sizeof ptr2 << std::endl; // 8 
    return 0; 
} 

ptr1ptr2作業問わず、それがstd::freeへのポインタを格納する必要がないため、ptr2は半分のサイズです。

私の質問:fn_tfn_refを定義する必要がないように、標準ライブラリの方法がありますか?

+1

機能はタイプです。 –

+1

@JoelCornett:関数は型ではありません。型引数として 'std :: free'を指定しようとすると、コンパイラは"型/値の不一致がテンプレートパラメータリストの引数1にあります "("型が予期しています。関数*は型を持ちますが、関数*は型ではありません。関数の型は、その関数に固有のものではありません。 'decltype(std :: free)'は 'void(void *)throw()'であり、この型には 'operator()'はありません。 –

+0

私の一部に「タイプo」だったhaha whoops。私はその逆を意味しました。 –

答えて

5

std::integral_constantが仕事をしているがあります:

using CFree = std::integral_constant<void (*)(void*), std::free>; 

それはその値に変換することができると、あなたは同じ構文を使用することができますoperator()に電話してください。

Demo

+2

:)巧妙ですが、私はまだカスタムファンクタを書くことがより表現力があると思います。 –

+1

また、 'integral_constant'は独自の' operator() 'を持っています。つまり、これはパラメータのない関数では機能しません。 –

+0

狡猾!私は 'std :: integral_constant <…> :: operator value_type'に慣れていませんでした。 @ T.C。このトリックがnullary関数のために働くのを妨げる 'operator()'についての良い点がありますが、関数シグネチャに関数リファレンスを埋めたいと思うたびに、関数は少なくとも1つの引数を取っています私はこの答えを受け入れます。ありがとうございました! –

1

短い答えは、いいえです。

しかし、単純なファンクタ型を作成して、必要な機能を呼び出すだけでは、より簡潔で(さらにキーストロークが少なくて済むかもしれない)と主張するかもしれません。

私の気持ちが、これはについて推論する方が簡単であるということである。

#include <cstring> 
#include <iostream> 
#include <memory> 

// Implementation: 

struct invoke_free 
{ 
    void operator()(void*p) const noexcept { 
    std::free(p); 
    } 
}; 

template <typename T> 
using unique_c_ptr = std::unique_ptr<T, invoke_free>; 

// Example use case: 


int main() { 

    // { char *, fn_t<void, void *>::fn_ref<std::free> } (8 bytes) 
    unique_c_ptr<char[]> ptr2(::strdup("Hello")); 

    std::cout << sizeof ptr2 << std::endl; // 8 
    return 0; 
} 
+1

* "短い答えは、いいえ" *私の答えを見てください。 – Jarod42

関連する問題