2016-12-24 103 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