[英]Why is narrowing conversion not preventing this map.insert() of an incorrect type from failing?
When inserting a std::pair<uint64_t, uint64_t>
to a C++ std::map<uint64_t, int>
, neither the compiler nor the program complains, even if the passed values are not possible for the data type uint64_t
. 将
std::pair<uint64_t, uint64_t>
插入到C ++ std::map<uint64_t, int>
,编译器和程序都不会抱怨,即使数据类型uint64_t
无法传递值也是如此。
In other words, the narrowing conversion of std::pair<uint64_t, uint64_t>(2, -2)
isn't working and is defaulting to the map's type std::map<uint64_t, int>
换句话说,
std::pair<uint64_t, uint64_t>(2, -2)
的缩小转换不起作用,并且默认为地图的类型std::map<uint64_t, int>
When I compile and execute the following code with g++ -Wall -Wconversion -Wextra -pedantic test/test_wrong_insert.cpp && ./a.out
: 当我使用
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);
}
... this is the output: ......这是输出:
Tried to insert std::pair<uint64_t, uint64_t>(2,-2). Return: 1
The map is now: {(2,-2) }
Why does std::pair<uint64_t,uint64_t> x{-1,-2}
not produce an error, and how do I make it cause an error? 为什么
std::pair<uint64_t,uint64_t> x{-1,-2}
不会产生错误,如何使其导致错误?
Why does
std::pair<uint64_t,uint64_t> x{-1,-2}
not produce an error?为什么
std::pair<uint64_t,uint64_t> x{-1,-2}
不会产生错误?
This is caused by a constructor template that participates in overload resolution when both arguments can be used to construct objects of uint64_t
(or whatever type you instantiated std::pair
with). 这是由参与重载解析的构造函数模板引起的,当两个参数都可以用于构造
uint64_t
对象(或者您实例化std::pair
with的任何类型)。 It is overload (3) in the list of std::pair
constructors , and its template argument deduction leads to a conversion that is taken as intentional (as in auto n = uint64_t{-42};
or static_cast<uint64_t>(-42);
) - hence no warning. 它是
std::pair
构造函数列表中的重载(3),其模板参数推导导致转换为有意转换(如auto n = uint64_t{-42};
或static_cast<uint64_t>(-42);
) - 因此没有警告。 There's not much you can do about it, as the template parameters of a constructor template can't be given explicitly, as explained here . 您无法做到这一点,因为无法明确给出构造函数模板的模板参数,如此处所述 。
[...] how to make it cause an error?
[...]如何使它导致错误?
Use std::make_pair
and don't rely on template argument deduction: 使用
std::make_pair
并且不依赖于模板参数推导:
auto p = std::make_pair<uint64_t, uint64_t>(-42, -42);
// Be explicit: ^^^^^^^^ ^^^^^^^^
When you compile the above snippet with -Wsign-conversion
(important: -Wconversion
won't cath it!), it will give you a warning (obviously, add -Werror
to treat it as an error). 当您使用
-Wsign-conversion
编译上述代码段时(重要: -Wconversion
不会-Wconversion
它!),它会给您一个警告(显然,添加-Werror
将其视为错误)。
The issue with std::map::insert
is the same, see overload (2) here . 这个问题
std::map::insert
是一样的,(2)见超载这里 。 This turns any usable given argument into a value_type
object, and treats it as any conversion would be the caller's intention. 这将任何可用的给定参数转换为
value_type
对象,并将其视为任何转换将是调用者的意图。 Interestingly, the equivalent member function on a std::set
is more restricted. 有趣的是,
std::set
上的等效成员函数更受限制。 So this is caught: 所以这被抓住了:
std::set<uint64_t> s;
s.insert(-42); // complains with -Wsign-conversion
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.