11

作为一个更大项目的一部分,我正在使用std::tuple模板;考虑以下代码:

template <typename ...T> void foo(tuple<T...> t) {}
void bar(tuple<int, char> t) {}
tuple<int, char> quxx() { return {1, 'S'}; }

int main(int argc, char const *argv[])
{
    foo({1, 'S'});           // error
    foo(make_tuple(1, 'S')); // ok
    bar({1, 'S'});           // ok
    quxx();                  // ok
    return 0;
}

根据这个答案C++17 支持来自copy-list-initialization 的元组初始化,但是似乎这种支持是有限的,因为我收到以下错误(GCC 7.2.0):

main.cpp: In function 'int main(int, const char**)':
main.cpp:14:17: error: could not convert '{1, 'S'}' from '<brace-enclosed initializer list>' to 'std::tuple<>'
     foo({1, 'S'}); // error
                 ^

在这种情况下,有什么方法可以使用大括号括起来的语法吗?

一些上下文:这将在运算符重载中使用,所以我想我被绑定到元组并且不能使用可变参数,任何提示都被很好地接受。

额外:Clang 6 也抱怨

prog.cc:12:5: error: no matching function for call to 'foo'
    foo({1, 'S'});           // error
    ^~~
prog.cc:6:31: note: candidate function [with T = <>] not viable: cannot convert initializer list argument to 'tuple<>'
template <typename ...T> void foo(tuple<T...> t) {}
4

2 回答 2

9

像 一样的花括号初始化列表{1, 'S'}实际上没有类型。在模板推导的上下文中,您只能在某些情况下使用它们 - 推导时initializer_list<T>T函数模板参数在哪里)或相应参数已经由其他东西推导时。在这种情况下,这两件事都不是真的 - 所以编译器无法弄清楚...T应该是什么。

所以你可以直接提供类型:

foo<int, char>({1, 'S'});

或者您可以tuple自己构建并将其传递给:

foo(std::tuple<int, char>(1, 'S')); // most explicit
foo(std::tuple(1, 'S')); // via class template argument deduction

今天,ClassTemplate<Ts...>只能从ClassTemplate<Us...>继承自类似事物的类型或类型的表达式中推导出来。一个假设的提议可以将其扩展为额外尝试对表达式执行类模板参数推导,以查看该推导是否成功。在这种情况下,{1, 'S'}不是一个tuple<Ts...>tuple __var{1, 'S'}确实成功地推断出tuple<int, char>这样就可以了。这样的提议还必须解决诸如......如果我们正在推断ClassTemplate<T, Ts...>或任何微小的变化会怎样,这不是类模板参数推断所允许的(但许多人有时表示有兴趣能够去做)。

我今天不知道有这样的提议。

于 2018-04-25T20:58:55.413 回答
2

根据这个答案 C++17 支持从复制列表初始化的元组初始化,但是似乎这种支持是有限的,因为我收到以下错误

问题是另一个。

当你调用bar({1, 'S'})时,编译器知道bar()接收一个tuple<int, char>,所以取1asint'S'as char

看另一个例子:如果你定义

void baz (std::tuple<int> const &)
 { }

你可以打电话

baz(1);

因为编译器知道baz()接收一个std::tuple<int>所以1要初始化int元组中的。

但随着

template <typename ...T>
void foo(tuple<T...> t)
 { }

编译器不知道T...类型;你打电话时

foo({1, 'S'}); 

什么T...类型应该推导出编译器?

我至少看到两个假设:T = int, charT = std::pair<int, char>; 或者也T = std::tuple<int, char>

哪个假设应该遵循编译器?

我的意思是:如果您将 a 传递std::tuplefoo(),编译器会接受元组中的类型列表作为T...;的列表。但是如果你传递了别的东西,编译器必须推断出正确的std::tuple;但在这种情况下,这种扣除并不是唯一的。所以错误。

于 2018-04-25T21:08:58.590 回答