C++ 警告:将_U1推断为 std::initializer_list<int>

C++ Warning: deducing _U1 as std::initializer_list<int>

本文关键字:list gt lt int initializer 警告 U1 C++ std      更新时间:2023-10-16

我正在使用g++-4.6.1 --std=c++0x并得到一个警告,我似乎无法破译这段代码:

#include <vector>
#include <tuple>
int main()
{
    std::tuple<std::vector<int>, int> t{ {1, 2, 3}, 10};
}

我得到以下警告:

scratch.cpp: In function ‘int main()’:
scratch.cpp:6:55: warning: deducing ‘_U1’ as ‘std::initializer_list<int>’ [enabled by default]
/usr/local/include/c++/4.6.1/tuple:329:9: warning:   in call to ‘std::tuple<_T1, _T2>::tuple(_U1&&, _U2&&) [with _U1 = std::initializer_list<int>, _U2 = int, _T1 = std::vector<int>, _T2 = int]’ [enabled by default]
scratch.cpp:6:55: warning:   (you can disable this with -fno-deduce-init-list) [enabled by default]

查看实现:

template<typename _T1, typename _T2>
class tuple<_T1, _T2> : public _Tuple_impl<0, _T1, _T2>
    {
      typedef _Tuple_impl<0, _T1, _T2> _Inherited;
    public:
      //...
      template<typename _U1, typename _U2>
        explicit
        tuple(_U1&& __a1, _U2&& __a2)
        : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { }
    //...
}

它似乎在抱怨它从initializer_list<int>(我的代码中的{1, 2, 3})转发到std::vector<int>,这将是std::tuple中的第一种类型。这对我来说完全没问题。

所以我的问题是:这个警告是什么意思?

这更像是一种猜测,而不是从标准中引用,但我认为它有一定的意义。

问题是一个用大括号括起来的列表可以表示很多东西。可以是初始化列表,但根据统一初始化,它也可以是任意数量的其他东西,例如聚合初始化器或简单的构造函数参数。

考虑以下情况:

struct Bar { Bar(int, int, int){} };
void foo(const std::vector<int> & v);
void zoo(const Bar & v);

我可以调用foo({1,2,3})zoo({1,2,3})。因为两个函数的参数类型都是已知的,所以没有歧义。然而foo的实参是一个初始化列表,而zoo的实参是一个统一初始化构造函数调用。

在元组的情况下,问题是所有涉及的类型都是模板。构造函数的实参类型必须是演绎的;在函数调用时,不知道。它的真正作用只在函数中显现。

由于构造元组成员的方法可能有很多种,因此此演绎可能是不明确的或完全错误的,因此编译器警告您它正在做假设

事实上,你可以很简单地构造一个这个假设的失败:

std::tuple<Bar, std::vector<int>> s{{1,2,3}, {1,2,3}};

构造第一个元组成员将失败,因为大括号列表的推导不正确。编写元组的唯一"好"方法是显式地:

std::tuple<Bar, std::vector<int>> s{Bar{1,2,3}, std::vector<int>{1,2,3}};

GCC是警告的,因为推导初始化列表是一个扩展。我假设这里的警告是一致的,因为它应该被视为来自实现的诊断。