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