2015-04-01 71 views
5

我有一個函數應該返回與該函數相同類型的std :: function。基本上我想這樣的事情:返回std :: function函數的返回類型

using RetType = std::function<RetType(void)>; 

顯然不會編譯。我如何正確地聲明返回類型?

+1

是否使用'auto'工作? – dwcanillas 2015-04-01 18:09:38

+0

@dwcanillas:喜歡[這個問題](http://stackoverflow.com/q/25338795/596781)? – 2015-04-01 18:10:17

+0

恩,我不知道我明白在這種情況下我會如何使用汽車。我必須聲明這個類型,然後自己定義這個函數。 – 2015-04-01 18:10:27

回答

4

你不能這樣使用std::function

你可以推出自己的,但它會需要一些工作。

這裏是一個草圖:

template<class T, class A, class B> 
struct sub{using type=T;}; 
template<class T, class A, class B> 
using sub_t=typename sub<T,A,B>::type; 
template<class T, class B> 
struct sub<T,T,B>{using type=B;}; 
template<class R,class...Args,class A,class B> 
struct sub<R(Args...),A,B>{ 
    using type=sub_t<R,A,B>(sub_t<Args,A,B>...); 
}; 

寫以上。它需要一個類型T,如果它匹配A它返回B。否則它返回T。它也適用於功能簽名。

我們可以在簽名與「標誌」類型時使用該函數對象本身的類型來代替:

struct recurse{}; // flag type 

// not needed in C++14: 
template<class Sig> 
using result_of_t=typename std::result_of<Sig>::type; 

template<class Sig> 
struct func { 
    using Sig2=sub_t<Sig,recurse,func>; 
    using function = std::function<Sig2>; 
    function impl; 
    template<class...Ts> 
    result_of_t<function const&(Ts...)> 
    operator()(Ts&&...ts)const 
    { 
    return impl(std::forward<Ts>(ts)...); 
    } 
}; 

然後func<recurse()>是一個函數對象,調用它時,返回func<recurse()>

原來,實現和存儲std::function<Sig2>一樣簡單,然後調用它。上面的代碼缺少打磨 - 你想要的構造,更多的運營商,隱私等

live example

注意,如果你想避免捕捉到自己的副本的Y組合子可能是有用的通過引用來返回*this在lambda中,因爲通過引用捕獲意味着有限的生命週期(並避免使用共享ptr)。

其他有用的工作是增強sub以處理引用到A甚至包含A作爲參數的模板。 (通用子算法在C++中不可行,因爲C++沒有完整的元模板功能,但是處理當前在std中的每個模板類都很容易:它們都是純粹的類型模板,或者是std::array)。


爲了完整起見,你可以添加這sub

// optional stuff for completeness: 
template<class T,class A,class B> 
struct sub<T&,A,B>{ 
    using type=sub_t<T,A,B>&; 
}; 
template<class T,class A,class B> 
struct sub<T*,A,B>{ 
    using type=sub_t<T,A,B>*; 
}; 
template<template<class...>class Z,class... Ts,class A,class B> 
struct sub<Z<Ts...>,A,B>{ 
    using type=Z<sub_t<Ts,A,B>...>; 
}; 
template<template<class,size_t>class Z,class T,size_t n,class A,class B> 
struct sub<Z<T,n>,A,B>{ 
    using type=Z<sub_t<T,A,B>,n>; 
}; 
template<class T,size_t n,class A,class B> 
struct sub<T[n],A,B>{ 
    using type=sub_t<T,A,B>[n]; 
}; 
template<class T,class A,class B> 
struct sub<T[],A,B>{ 
    using type=sub_t<T,A,B>[]; 
}; 
template<class T,class A,class B> 
struct sub<T const,A,B>{ 
    using type=sub_t<T,A,B> const; 
}; 
template<class T,class A,class B> 
struct sub<T volatile const,A,B>{ 
    using type=sub_t<T,A,B> volatile const; 
}; 
template<class T,class A,class B> 
struct sub<T volatile,A,B>{ 
    using type=sub_t<T,A,B> volatile; 
}; 

,現在可遞歸許多模板,陣列上,引用和指針,與CV-合格的類型。這允許你寫類似:

func< std::vector<recurse>() > 

這是一個函數對象,其operator()返回func< std::vector<recurse>() >

請注意,此過程並不完美,好像some_template<recurse>不是有效的模板實例化,上述操作將不起作用。一個陌生的版本,可能會應用模板和參數,在這種情況下,需要替換,然後是應用程序。

+0

你有演示嗎? – 2015-04-01 18:50:54

+0

@KerrekSB我現在在做。 – Yakk 2015-04-01 19:43:44