std::只有一个初始化列表参数的非平凡类的配对初始化

问题描述 投票:0回答:3

考虑以下代码:

#include <utility>
#include <vector>

using V = std::vector<int>;

int main() {
    std::pair<int, V> p1{1, 2};   // p1.second has 2 elements
    std::pair<int, V> p2{1, {2}}; // p2.second has 1 element

    std::pair<V, V> p3{2, 2};     // Both vectors have 2 elements
    std::pair<V, V> p4{{2}, {2}}; // Both vectors have 1 element

    std::pair<V, V> p5{2, {2}};   // Does not compile
    // p5.first should have 2 elements, while the other should have 1
}

我的主要问题是最后一行

p5
,它不使用
g++-12
编译,但使用
g++-10
编译。我想知道:

  • 导致此问题的更改是什么?
  • 是否可以再次编译而无需构建向量和 复制它们(即不要在某处使用
    V(2)

我也试过玩

std::piecewise_construct
但我不确定这是正确的解决方案。

错误:

<source>: In function 'int main()':
<source>:9:30: error: no matching function for call to 'std::pair<std::vector<int>, std::vector<int> >::pair(<brace-enclosed initializer list>)'
    9 |     std::pair<V, V> p3{2, {2}};
      |                              ^
In file included from /opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/utility:69,
                 from <source>:1:
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:354:9: note: candidate: 'template<class _U1, class _U2>  requires  _S_constructible<_U1, _U2>() && _S_dangles<_U1, _U2>() constexpr std::pair<_T1, _T2>::pair(std::pair<_U1, _U2>&&) [with _U2 = _U1; _T1 = std::vector<int>; _T2 = std::vector<int>]' (deleted)
  354 |         pair(pair<_U1, _U2>&&) = delete;
      |         ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:354:9: note:   template argument deduction/substitution failed:
<source>:9:30: note:   mismatched types 'std::pair<_T1, _T2>' and 'int'
    9 |     std::pair<V, V> p3{2, {2}};
      |                              ^
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:345:9: note: candidate: 'template<class _U1, class _U2>  requires  _S_constructible<_U1, _U2>() && !_S_dangles<_U1, _U2>() constexpr std::pair<_T1, _T2>::pair(std::pair<_U1, _U2>&&) [with _U2 = _U1; _T1 = std::vector<int>; _T2 = std::vector<int>]'
  345 |         pair(pair<_U1, _U2>&& __p)
      |         ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:345:9: note:   template argument deduction/substitution failed:
<source>:9:30: note:   mismatched types 'std::pair<_T1, _T2>' and 'int'
    9 |     std::pair<V, V> p3{2, {2}};
      |                              ^
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:339:9: note: candidate: 'template<class _U1, class _U2>  requires  _S_constructible<const _U1&, const _U2&>() && _S_dangles<const _U1&, const _U2&>() constexpr std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U2 = _U1; _T1 = std::vector<int>; _T2 = std::vector<int>]' (deleted)
  339 |         pair(const pair<_U1, _U2>&) = delete;
      |         ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:339:9: note:   template argument deduction/substitution failed:
<source>:9:30: note:   mismatched types 'const std::pair<_T1, _T2>' and 'int'
    9 |     std::pair<V, V> p3{2, {2}};
      |                              ^
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:330:9: note: candidate: 'template<class _U1, class _U2>  requires  _S_constructible<const _U1&, const _U2&>() && !_S_dangles<_U1, _U2>() constexpr std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U2 = _U1; _T1 = std::vector<int>; _T2 = std::vector<int>]'
  330 |         pair(const pair<_U1, _U2>& __p)
      |         ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:330:9: note:   template argument deduction/substitution failed:
<source>:9:30: note:   mismatched types 'const std::pair<_T1, _T2>' and 'int'
    9 |     std::pair<V, V> p3{2, {2}};
      |                              ^
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:323:9: note: candidate: 'template<class _U1, class _U2>  requires  _S_constructible<_U1, _U2>() && _S_dangles<_U1, _U2>() constexpr std::pair<_T1, _T2>::pair(_U1&&, _U2&&) [with _U2 = _U1; _T1 = std::vector<int>; _T2 = std::vector<int>]' (deleted)
  323 |         pair(_U1&&, _U2&&) = delete;
      |         ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:323:9: note:   template argument deduction/substitution failed:
<source>:9:30: note:   couldn't deduce template parameter '_U2'
    9 |     std::pair<V, V> p3{2, {2}};
      |                              ^
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:315:9: note: candidate: 'template<class _U1, class _U2>  requires  _S_constructible<_U1, _U2>() && !_S_dangles<_U1, _U2>() constexpr std::pair<_T1, _T2>::pair(_U1&&, _U2&&) [with _U2 = _U1; _T1 = std::vector<int>; _T2 = std::vector<int>]'
  315 |         pair(_U1&& __x, _U2&& __y)
      |         ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:315:9: note:   template argument deduction/substitution failed:
<source>:9:30: note:   couldn't deduce template parameter '_U2'
    9 |     std::pair<V, V> p3{2, {2}};
      |                              ^
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:238:9: note: candidate: 'template<class ... _Args1, long unsigned int ..._Indexes1, class ... _Args2, long unsigned int ..._Indexes2> constexpr std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {_Args1 ...}; long unsigned int ..._Indexes1 = {_Indexes1 ...}; _Args2 = {_Args2 ...}; long unsigned int ..._Indexes2 = {_Indexes2 ...}; _T1 = std::vector<int>; _T2 = std::vector<int>]'
  238 |         pair(tuple<_Args1...>&, tuple<_Args2...>&,
      |         ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:238:9: note:   template argument deduction/substitution failed:
<source>:9:30: note:   mismatched types 'std::tuple<_UTypes ...>' and 'int'
    9 |     std::pair<V, V> p3{2, {2}};
      |                              ^
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:202:9: note: candidate: 'template<class ... _Args1, class ... _Args2> constexpr std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {_Args1 ...}; _Args2 = {_Args2 ...}; _T1 = std::vector<int>; _T2 = std::vector<int>]'
  202 |         pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>);
      |         ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:202:9: note:   template argument deduction/substitution failed:
<source>:9:30: note:   candidate expects 3 arguments, 2 provided
    9 |     std::pair<V, V> p3{2, {2}};
      |                              ^
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:305:7: note: candidate: 'constexpr std::pair<_T1, _T2>::pair(const _T1&, const _T2&) requires  _S_constructible<const _T1&, const _T2&>() [with _T1 = std::vector<int>; _T2 = std::vector<int>]'
  305 |       pair(const _T1& __x, const _T2& __y)
      |       ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:305:23: note:   no known conversion for argument 1 from 'int' to 'const std::vector<int>&'
  305 |       pair(const _T1& __x, const _T2& __y)
      |            ~~~~~~~~~~~^~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:249:7: note: candidate: 'constexpr std::pair<_T1, _T2>::pair() requires (is_default_constructible_v<_T1>) && (is_default_constructible_v<_T2>) [with _T1 = std::vector<int>; _T2 = std::vector<int>]'
  249 |       pair()
      |       ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:249:7: note:   candidate expects 0 arguments, 2 provided
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:198:17: note: candidate: 'constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = std::vector<int>; _T2 = std::vector<int>]'
  198 |       constexpr pair(pair&&) = default;         ///< Move constructor
      |                 ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:198:17: note:   candidate expects 1 argument, 2 provided
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:197:17: note: candidate: 'constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = std::vector<int>; _T2 = std::vector<int>]'
  197 |       constexpr pair(const pair&) = default;    ///< Copy constructor
      |                 ^~~~
/opt/compiler-explorer/gcc-trunk-20230315/include/c++/13.0.1/bits/stl_pair.h:197:17: note:   candidate expects 1 argument, 2 provided
Compiler returned: 1
c++ initialization language-lawyer c++20 std-pair
3个回答
3
投票

这看起来像一个错误fix。没有正确实现的 C++ 版本,其中:

std::pair<V, V> p5{2, {2}};

会编译。

A braced-init-list/initializer 列表(注意缺少“_”) 不是表达式;它是自己独立的语法结构。它参与模板参数推导的方式真的很简单

(大部分)。

如果相应的参数明确地是某种

initializer_list<E>
,那么它可以推导出
E
。否则它不能并且参数是非推导的

如果从 P 中移除引用和 cv 限定符给出 std::initializer_list 或 P′[N] 对于某些 P′ 和 N 并且参数是非空初始化列表 ([dcl.init.list]),则推导而是对初始化列表的每个元素独立执行,将 P' 作为单独的函数模板参数类型 P'i 和第 i 个初始化元素作为相应的参数。 在 P'[N] 的情况下,如果 N 是非类型模板参数,则 N 从初始化列表的长度推导出来。 否则,初始化列表参数会导致参数被视为非推导上下文([temp.deduct.type])。

这是重复的

关联参数是初始化列表([dcl.init.list])但参数没有指定从初始化列表中扣除的类型的函数参数([temp.deduct.call])。

当然,如果无法推导模板参数,则模板参数推导失败,并且无法调用该函数。

如果模板参数仅用于非推导上下文且未明确指定,则模板参数推导失败。

这意味着像这样的构造函数:

template< class U1, class U2 >
pair( U1&& x, U2&& y );

不会在 braced-init-lists 上工作。因此,

{2, {2}}
唯一可行的构造函数是第二个参数不是需要推导的模板参数的构造函数。

这基本上意味着这个:

pair(const T1& x, const T2& y);

T1
T2
来自类模板参数,而不是函数模板的参数。您已经将它们指定为
V
V
,因此尝试调用它。

但是,

vector<int>
不能从整数 2 隐式转换。采用单个整数的构造函数是
explicit
,因此尝试初始化
x
将失败。

此构造函数自 C++98 以来一直是显式的。所以

std::pair<V, V> p5{2, {2}};
应该never有效。如果是这样,这是实施中的一个错误。


是否可以再次编译它而不必构建向量并将它们复制进去(即不在某处使用 V(2))

从来没有奏效。它总是复制.

您可以使用

piecewise_construct
initializer_list
体操来避免“复制”。但实际上,只需切换到使用
tuple
并在初始化列表中正确使用类型:

std::tuple<V, V> p5{V{2}, V{2}};

或者,减少冗余:

std::tuple p5{V{2}, V{2}};

这将从参数中移动,而不是从中复制。


0
投票

这是一个 libstdc++ 错误。

您的示例中仅涉及以下

pair
构造函数([pairs.pair]):

template<class U1 = T1, class U2 = T2>
  constexpr explicit(see below) pair(U1&& x, U2&& y);

对于

std::pair<V, V> p{2, 2}
U1
/
U2
将被推导为
int&
,并且
V
将在内部显式构造。

对于

std::pair<V, V> p{{2}, {2}}
U1
/
U2
将默认为
T1/T2
V
,因为
V&&
可以从
std::initializer_list
构造。

对于

std::pair<V, V> p{2, {2}}
U1
将被推导为
int&
,而
U2
将默认为
V


libstdc++ 删除了非标准的

std::pair
构造函数,例如
pair(U1&&, const T2&)
以修复 PR 99957,这使得它不再适用于您的示例。


-2
投票

我不知道为什么,但是编译器无法在

{2}
中找出
p5
的类型。告诉它可以解决您的问题。

#include <utility>
#include <vector>

using V = std::vector<int>;

int main() {
    std::pair<int, V> p1{1, 2};   // p1.second has 2 elements
    std::pair<int, V> p2{1, {2}}; // p2.second has 1 element

    std::pair<V, V> p3{2, 2};     // Both vectors have 2 elements
    std::pair<V, V> p4{{2}, {2}}; // Both vectors have 1 element

    std::pair<V, V> p5{2, V{2}};   // Does not compile
    // p5.first should have 2 elements, while the other should have 1
}
© www.soinside.com 2019 - 2024. All rights reserved.