将std::pair<uint64_t, uint64_t>
插入C ++ std::map<uint64_t, int>
时,即使数据类型uint64_t
不可能传递值,编译器和程序也不会抱怨。
换句话说,std::pair<uint64_t, uint64_t>(2, -2)
的缩小转换不起作用,并且默认为地图类型std::map<uint64_t, int>
当我使用g++ -Wall -Wconversion -Wextra -pedantic test/test_wrong_insert.cpp && ./a.out
编译并执行以下代码时:
#include<map>
#include<iostream>
void print_map(std::map<uint64_t, int> & m){
std::cout << "The map is now: {";
for (const auto & n: m){
std::cout << '(' << n.first << ',' << n.second << ") ";
}
std::cout << "}\n";
}
int main(){
std::map<uint64_t, int> m;
auto ret = m.insert(std::pair<uint64_t, uint64_t>(2,-2));
std::cout << "Tried to insert std::pair<uint64_t, uint64_t>(2,-2). ";
std::cout << "Return: " << ret.second << '\n';
print_map(m);
}
...这是输出:
Tried to insert std::pair<uint64_t, uint64_t>(2,-2). Return: 1
The map is now: {(2,-2) }
为什么std::pair<uint64_t,uint64_t> x{-1,-2}
不产生错误,如何使它引起错误?
答案 0 :(得分:4)
std::pair<uint64_t,uint64_t> x{-1,-2}
为什么不产生错误?
这是由构造器模板引起的,该构造器模板可同时使用两个参数来构造uint64_t
(或实例化std::pair
的任何类型)的对象时参与重载解析。 std::pair
constructors列表中的重载(3),其模板参数推导导致转换为故意(如auto n = uint64_t{-42};
或static_cast<uint64_t>(-42);
)-因此没有警告。您无能为力,因为explained here无法明确给出构造函数模板的模板参数。
[...]如何使其引起错误?
使用std::make_pair
,不要依赖模板参数推导:
auto p = std::make_pair<uint64_t, uint64_t>(-42, -42);
// Be explicit: ^^^^^^^^ ^^^^^^^^
当您使用-Wsign-conversion
编译以上代码段时(重要的是-Wconversion
不会起作用!),它将发出警告(显然,添加-Werror
会将其视为错误)。
std::map::insert
的问题是相同的,请参见重载(2)here。这会将任何可用的给定参数转换为value_type
对象,并将其视为任何转换都是调用者的意图。有趣的是,std::set
上的等效成员函数受到更多限制。所以这被抓住了:
std::set<uint64_t> s;
s.insert(-42); // complains with -Wsign-conversion