2

基地問題

基礎問題我試圖解決推斷「自動」是這樣的:無法從「tuple_cat」

我有一個模板參數包ArgTypes,我需要做一個元組每個類型都包裝在std :: optional中。例如:make_optional_tuple<int, double, std::string>應該返回一個元組元組的元組元組,其元素元組的初始值爲std::nullopt

我的工作至今

我使用附帶GCC 7.1 g++。我一直在與C++類型系統搏鬥了很長一段時間,我的代碼只適用於一種類型,但不適用於多種類型。我在參數包與多種類型得到的錯誤是:

error: unable to deduce 'auto' from 'tuple_cat<std::make_tuple(_Elements&& ...) [with _Elements = {std::optional<int>&}](), optional_tuple>'

有誰知道我怎麼能解決這個問題?直覺上(儘管我可能不正確),我認爲問題在於C++類型系統無法推導出auto optional_tuple的類型,因爲它涉及完全解決由參數包產生的不同函數模板的遞歸鏈 - 也許可能類型系統在嘗試解析變量類型時無法執行此操作。

這裏是一個最小的工作例如:

#include <optional> 
#include <tuple> 

template<int n, typename ArgType, typename... ArgTypes> 
struct make_optional_tuple_helper { 
    static auto tuple() { 
     std::optional<ArgType> optional_arg = {}; 
     auto optional_tuple = make_optional_tuple_helper<n-1, ArgTypes...>::tuple(); 
     return std::tuple_cat<std::make_tuple(optional_arg), optional_tuple>; 
    } 
}; 

template<typename ArgType> 
struct make_optional_tuple_helper<1, ArgType> { 
    static std::tuple<std::optional<ArgType>> tuple() { 
     std::optional<ArgType> optional_arg = {}; 
     return std::make_tuple(optional_arg); 
    } 
}; 

template<typename... ArgTypes> 
auto make_optional_tuple() { 
    return make_optional_tuple_helper<std::tuple_size<std::tuple<ArgTypes...>>::value, ArgTypes...>::tuple(); 
}; 

int main() { 
    auto i = make_optional_tuple<int>(); // works! 
    auto j = make_optional_tuple<int, double>(); // error: unable to deduce 'auto'... 
} 

(與g++-7 -std=c++1z example.cpp編譯)

感謝您的時間和/或幫助!

回答

3

您是方式得太多這樣的:

template<typename... ArgTypes> 
auto make_optional_tuple() { 
    return std::tuple<std::optional<ArgTypes>...>{}; 
} 

由於缺省構造可選是nullopt,這就是你所需要的。


具體問題是你用錯括號:

return std::tuple_cat<std::make_tuple(optional_arg), optional_tuple>; 
        ~~~           ~~~ 

那些應該是括號。按原樣,您將返回一個指向格式不正確的函數模板特化的指針,而不是元組。

+0

感謝您的回答。的確是這個問題。我不會說太多的「過度思考」,更像是「對參數包沒有足夠的瞭解」。儘管如此,你在這裏寫的比我所擁有的一切都要乾淨得多。我試圖理解這裏的語法 - 特別是'std :: optional ...'部分。我所看到的所有例子都有緊跟着模板參數名稱的省略號,例如'ArgTypes ...'。如果我要求你再解釋一下這個語法,你介意嗎? – user3831357

+0

@ user3831357 [我對此問題的回答](https://stackoverflow.com/a/26767333/2069064) – Barry

-2

它不起作用,因爲函數的返回類型是在第一次返回時推導出來的,並且您試圖在第一次返回之前調用該函數。

我相信你可以做一些長的線路:

template<typename... ArgTypes> 
struct make_optional_tuple_helper { 
    static auto tuple() { 
     return std::make_tuple(std::optional<ArgTypes>()...); 
    } 
}; 

或者

template<typename... ArgTypes> 
struct make_optional_tuple_helper { 
    static auto tuple() { 
     return std::tuple<std::optional<ArgTypes>...>(); 
    } 
}; 
+0

感謝您的回答。你能否詳細說明你在第一次迴歸時推論的意思?我理解的方式是,遞歸的設置方式是調用堆棧一直遍歷最終的模板特化(即,'make_optional_tuple_helper <1, ArgType>')在返回任何語句之前;並且由於第一個示例(參數包中包含一種類型)起作用,所以此基本案例的返回類型是可以推論的。 – user3831357

+0

對,我錯過了 – lapinozz

+0

我看到它,你正在調用tuple_cat <>而不是tuple_cat() – lapinozz