C++ 使用(模板化的)已删除函数重载来防止通常的算术转换
我经常发现我希望防止特定构造函数或函数的收缩或符号转换(通常是)。我倾向于写:C++ 使用(模板化的)已删除函数重载来防止通常的算术转换,c++,implicit-conversion,C++,Implicit Conversion,我经常发现我希望防止特定构造函数或函数的收缩或符号转换(通常是)。我倾向于写: #include <iostream> void foo(double f){ std::cout << "foo double" << f <<std::endl; } void foo(float) = delete; // or template<typename T> void foo(T&& f) = delete; v
#include <iostream>
void foo(double f){
std::cout << "foo double" << f <<std::endl;
}
void foo(float) = delete;
// or template<typename T> void foo(T&& f) = delete;
void bar(unsigned int f){
std::cout << "bar uint " << f <<std::endl;
}
void bar(signed int ) = delete;
// or template<typename T> void bar(T&& f) = delete;
现在,在这些情况下,如果我使用删除的模板或删除的非模板函数,这仅仅是一个品味问题,还是在某些情况下它很重要?我发现删除的模板更明确,可以防止所有的T,但另一方面,在构造函数中使用此模式时;转发构造函数。
对于模板化版本,是否最好将已删除的模板改为常量T&?首先,我认为值得注意的是,非模板版本会阻止大多数情况,因为它们会导致两个重载之间的歧义,而模板重载通过提供比非模板重载更好的匹配来实现。因此,由模板版本生成的错误消息将更清晰,类似于“您已尝试调用此已删除函数”,而不是“我无法在这两个函数之间做出决定,您实际上想要哪一个?”。从这个角度来看,模板版本看起来更好 然而,在某些情况下,情况会有所不同 一个模糊的例子是
foo({f})代码>,模板版本不阻止此操作,因为初始值设定项列表使参数成为非推断上下文,因此模板的推断失败,只留下非模板重载
出于类似的原因,模板版本将阻止foo({i})代码>但不会阻止foo({3})
(3
是一个常数,因此到double
的转换不是缩小转换,因为3
适合于double
并在转换回时生成相同的值)。非模板版本会同时阻止这两个,因为它们都是不明确的
另一种情况:
enum E : unsigned { };
int main()
{
E e{};
bar(e);
}
模板版本通过提供最佳重载来防止这种情况。非模板的一个没有,因为E
到unsigned int
是一种提升,比E
到int
更好,后者是一种转换
类似的问题也会出现在平台上,例如,short
与int
大小相同的平台,以及从char16\u t
、char32\u t
或wchar\u t
转换的平台,具体取决于它们的平台表示
虽然问题的上下文可能不太有趣,但另一个不同之处在于:
struct A
{
operator double() { return 7.0; }
};
int main()
{
A a{};
foo(a);
}
模板版本通过提供最佳重载防止了这种情况,而非模板版本则没有(调用foo(double)
)。或者干脆t
(template void foo(t)=delete;
)@Jarod42。对…一个模糊的情况,事情表现不同,类似于foo({f})代码>,模板版本不阻止此操作,因为初始值设定项列表使参数成为非推断上下文,因此模板的推断失败,只留下非模板重载。(我无法打开问题中的链接,我不知道是否有提及。)@bogdan,这正是我希望在这些问题中找到的例子。使用init列表的隐式转换非常可怕。然后可以添加模板void foo(std::initializer_list)=delete
我认为在许多用例中不捕捉foo({f})
是可以的,因为大括号已经阻止了变窄。@T.C.我同意,但OP想要阻止foo(f)代码>,因此不阻止带括号的版本感觉不一致。我主要是想找出两种方法产生不同结果的情况。我在避免做出阻止或允许的决定——这对我来说太难了。@T.C.,我不明白。f=1.5f和foo({f})正在将1.5f转换为1U@JohanLundberg GCC对foo({f})
发出警告,对foo({1.5f)
发出错误。Clang和MSVC对这两个问题都发出错误。
struct A
{
operator double() { return 7.0; }
};
int main()
{
A a{};
foo(a);
}