2014-08-27 17 views
3

tuple continuation monad之後,說我定義了一個函子std_tuple從單子元組的cathegory去std::tuple繼續延續單子元組。怎麼了?

auto std_tuple = [](auto... args) 
{ 
    return [=](auto f){ return f(std::make_tuple(args...)); }; 
}; 

現在我們可以在上下文中使用單子元組期待std::tuple

template<typename... ARGS> 
void f(const std::tuple<ARGS...>& t){} 

int main() 
{ 
    tuple(1,2,3)(std_tuple)(f); 
} 

到目前爲止好。除此之外不編譯。 3.4.1鏗鏘抱怨:

注:忽略候選模板:無法推斷出模板參數 '$自動1-0'

std_tuple仿函數裏面的f(t)電話。

這是正確的,是不是那些模板argumments可扣除?如果是肯定的,爲什麼?

+0

的應用閉合類型的操作是一樣'模板 decltype(自動)操作者的功能模板()(T)',它不能推斷出類型只是ID-表達'F'。你可以將'f'換成lambda,'[](auto const&t){return f(t); }' – dyp 2014-08-27 18:02:48

+1

對於C++ 14的多態lambda表達式,完美轉發lambda包裝來傳遞重載集合是非常有用的。不幸的是,這是一些沒有宏的樣板文件:'#define LAMBDA_WRAP(FUN)([](auto && ... args){return FUN(std :: forward (args)...);}) ' – dyp 2014-08-27 18:10:25

+0

@dyp爲什麼'()'在lambda周圍? – Yakk 2014-08-27 19:43:27

回答

4

再現您的問題一個簡單的例子:

void f(int) {} 
void f(double) {} 

template<class T> void call_with_3(T t) { t(3); } 

int main() { 
    call_with_3(f); 
} 

在這裏我們可以看到,f調用不能在這裏我們把它傳遞給call_with_3點確定。現在,您看起來沒有多重過載(您只有一個f!),但是...

A template不是一個實例。 A template函數是函數的工廠,而不是函數。

沒有任何東西可以傳遞。

當您將函數名稱作爲參數傳遞時,重載決議開始執行。如果目標類型是已知的(作爲函數引用或指針),它將用於對函數名稱進行重載解析。

在這種情況下,您將函數名稱傳遞給templateauto參數),因此沒有可以完成的重載解析,因此沒有找到特定的值,因此會出現錯誤。

您可以創建一個對象,其效果是對給定函數名稱的調用參數執行重載解析。我稱它們爲重載集對象。

static struct f_overload_set_t { 
    template<class... Args> 
    auto operator()(Args&&... args) const { 
    return f(std::forward<Args>(args)...); 
    } 
} f_overload_set; 

在C++ 11你所需要的const->decltype(f(std::declval<Args>()...))

現在f_overload_set(blah)將被調用時將(幾乎)做什麼,當你f(blah),但f_overload_set是一個實際的對象。所以你可以傳遞它。

生成此類過載集的宏相對容易編寫。他們也可以使用lambdas,因爲如果你仔細想想,上面的內容很像無狀態的lambda。

無狀態的基於lambda的宏過載集生成器的好處是它可以在使用點創建。從上面@ DYP的評論:

#define OVERLOAD_SET(FUNC)\ 
    ([](auto&&... args){\ 
    return FUNC(std::forward<decltype(args)>(args)...);\ 
    }) 

(注:約FUNC沒有括號,如阻止ADL)。周圍的一切括號,因爲否則的話標操作(operator[])中,它會被解析爲[[開始的屬性,其他點之間(感謝@ecatmur))

使你的代碼:

template<typename... ARGS> 
void f(const std::tuple<ARGS...>& t){} 

int main() { 
    tuple(1,2,3)(std_tuple)(OVERLOAD_SET(f)); 
} 
+0

所以根本'運營商的()'簽名'模板自動操作( )(T)',我傳遞一個模板。當然'f'參數在這種情況下是不可推論的,這是有道理的。我只是忘記了一個通用的lambda實際是什麼。非常感謝。 – Manu343726 2014-08-27 20:17:29