为什么无法将std::pair与std::initializer_list进行比较?

4
对于 std::pair,我只是好奇为什么这样可以工作。
std::pair<int, int> response = {1, 2}

然而,这并不行:

if (response == {1, 2}) do something;

是不是因为 = 运算符对 std::pair 进行了重载,而 == 没有进行重载?


8
第一个不是初始化列表,而第二个是。Pair不能使用初始化列表,因为初始化列表是同质的,而pair是异质的数据结构。考虑pair<int, std::string> - bolov
1
第一个甚至不是operator=,它是list-initialization - Remy Lebeau
2个回答

2

这只是语法:大括号初始化列表只能作为[]()(内部)以及=和任何@=(右侧)的操作数。初始化情况也被允许,其中根本没有运算符。


谢谢!这方面有参考资料吗? - Enqueue
1
@Enqueue:我猜你指的不是标准中的语法——cppreference在列出列表初始化用途时进行了解释 - Davis Herring
因此,列表初始化与initializer_list不同,事实上,在执行列表初始化或在赋值期间用作右操作数时,后者的对象会自动创建。这种理解正确吗? - Enqueue
1
@Enqueue: 它们是不同的,而且一些列表初始化会生成std::initializer_list<T>对象,但是花括号初始化列表的内容也可以直接使用(包括作为构造函数参数)。 - Davis Herring

1

人们已经提供了答案。我只想补充一下。

编辑:第二个不是与std::initializer_list进行比较,实际上是无效的语法,因为像{1,2}这样的东西并没有任何固有的类型(尝试decltype({1,2}) x)。这是语言对list-initialization的语法,它失败了,因为这不是一个关于初始化本身的语句,不像x{1,2}/x = {1,2}/foo({1,2})等。像{1,2}这样的东西可以使用list-initialization构造一个initializer_list,但本身不是一个std::initializer_list

std::pairstd::initializer_list之间的比较运算符不可用,可能是有充分理由的,因为一个initializer_list一个轻量级代理对象,提供对类型为const T的对象数组的访问。

请注意,initializer_list的所有成员的类型都是相同的,即const T。这在pair的情况下并非如此,通常具有不同的类型TU

如果您愿意,您可以编写一个等于函数来比较pairinitializer_list,如下所示,当然要遵守许多约束:

#include <iostream>
#include <type_traits>
#include <utility>
#include <initializer_list>

template <typename T, typename U>
bool foo(const std::pair<T, U>&pair,
 const std::initializer_list<std::common_type_t<T, U>>& list) {
     if(list.size() != 2) {
         return false;
     }
     auto it = begin(list);
     return pair.first == *it && pair.second == *std::next(it);
}

int main() {
    {
        std::pair<int, int> pair {1, 3};
        std::initializer_list<int> list {1, 2};
        std::cout<<std::boolalpha<<foo(pair, list)<<'\n';
    }
    {
        std::pair<int, int> pair {1, 2};
        std::initializer_list<int> list {1, 2};
        std::cout<<std::boolalpha<<foo(pair, list)<<'\n';
    }
    {
        std::pair<int, int> pair {1, 2};
        std::initializer_list<int> list {1, 2, 3};
        std::cout<<std::boolalpha<<foo(pair, list)<<'\n';
    }
    {
        std::pair<int, char> pair {1, 2}; //common type is int
        std::initializer_list<int> list {1, 2};
        std::cout<<std::boolalpha<<foo(pair, list)<<'\n';
    }
    {
        // std::pair<int, long> pair {1, 2}; //common type is long int
        // std::initializer_list<int> list {1, 2}; //fails template substitution
        // std::cout<<std::boolalpha<<foo(pair, list)<<'\n';
    }
    {
        std::pair<int, long> pair {1, 2}; //common type is long int
        std::initializer_list<long int> list {1, 2}; //same as common type of pair
        std::cout<<std::boolalpha<<foo(pair, list)<<'\n';
    }
    {
        std::pair<int, long> pair {1, 2}; //common type is long int
        if(foo(pair, {1, 2})) {
            std::cout<<"Matched\n";
        }
    }
}

2
这不是与initializer_list的比较:它甚至无法解析,即使它能够解析,它仍然不会成为该类型或任何其他类型的表达式 - Davis Herring
@DavisHerring 没错,我已经修改了我的答案以反映这一点。 - Zoso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接