2016-12-24 74 views
4

我正在尋找一個標準的C++ 14類型模板,它靜態地(在編譯時)嵌入一個函數引用作爲模板參數,並實現operator()作爲對引用函數的轉發調用。是否有標準的靜態函數包裝類型模板?

我知道std::function存在,但它存儲一個函數指針作爲數據成員。我希望將函數引用嵌入到類型簽名中,以便封裝類型爲空的默認構造的

我有一個工作的實施(例如與用例):

#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工作一樣,但ptr2是成功的一半大小,因爲它並不需要存儲指向std::free

我的問題:是否有一個標準庫的方式來做到這一點,所以我不需要定義fn_tfn_ref

+1

函數是一種類型。 –

+1

@JoelCornett:函數不是一種類型。如果你試圖提供'std :: free'作爲類型參數,編譯器會發出一個錯誤:「模板參數列表中參數1的類型/值不匹配」(「注:預期類型,得到'空閒'」)。函數*有*類型,但函數*不是類型。並且函數的類型對於該函數不是唯一的。 'decltype(std :: free)'是'void(void *)throw()',這個類型沒有'operator()'。 –

+0

哈哈哎呀,這是我的'type-o'。我的意思是相反的。 –

回答

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。有一個關於'operator()'的好處,它將排除這個技巧無效的功能,但我想幾乎每次我想要在函數引用中嵌入一個函數引用時,函數至少需要一個參數,所以我會接受這個答案。謝謝! –

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