C++隐式类型转换字符串-> int?

c++ implicit type conversion string -> int?

当我只是想尝试以下程序时,我正在研究 C++ 类型。

void swap(int& a, int& b){
    int temp = a;
    a = b;
    b = temp;
    }


int main(){
    string a{"sssss"}, b{"ddddd"};
    swap(a,b); //this should not work!! but it does
    cout << a << ' '<<b <<endl;
    return 0;
    }

我没想到这会交换字符串,但确实如此!为什么这是有效的?虽然编译器会发出警告,但这不是错误!

// Assuming the following:
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
// or even using namespace std, though this
// would make std::swap a candidate even
// without ADL


// renaming shows that it's not this function
// that gets called ...
void myswap(int& a, int& b) {
  int temp = a;
  a = b;
  b = temp;
  // printing some output also reveals what's going on
}

int main() {
  string a{"sssss"}, b{"ddddd"};
  swap(a,b); // this is not calling your swap!
  // myswap(a,b) produces the error you expected
  cout << a << ' '<< b <<endl;
  return 0;
}

它没有调用你的交换函数。命名空间是一种接口,因此当一个人将自由函数声明为与它们操作的数据类型在同一命名空间中时,然后在没有适当的命名空间限定的情况下调用它们将起作用。

这称为 "argument dependent name lookup",或 ADL。

因此,当您在 std::string 上调用函数 swap 时,它还会在 std 命名空间中寻找候选项。并且因为有 std::swap,它可以应用于字符串,而不是你的全局命名空间中的其他候选者(因为你的交换只对整数进行操作),它将用于调用。


如上所示,您可以让您的函数生成调试输出或重命名它以轻松验证调用的不是您的函数。

附带说明:假设存在某种从字符串到整数的隐式转换。然后你会得到两个临时工。然后你的交换函数将被调用(实际上不是,因为 binding non const references to temporaries isn't allowed)并且这些整数被交换。然后?这不会对原始字符串产生任何影响。


最后,我不认为这段代码是可移植的。它仅在 header 字符串或 iostream 包含算法 header 时编译,并且这三个算法之一提供字符串的 std::swap 特化。但是由于标准似乎不能保证这一点,因此只有在您自己包含算法时,这段代码才能可靠地工作。

您的程序无法编译。我猜你实际上有以下几行但未能 post 它们:

#include <iostream>
#include <string>
using namespace std;

有一个标准模板std::swap。尽管这在 #include <algorithm> 中,但任何 header 都可能包含任何其他 header。因此,即使您没有特别包含它,它也可能已经包含在内了。

因此,当您调用不合格的 swap 时,您的 swapstd::swap 都包含在重载决策中。 (即使您没有 using namespace std;,命名空间 std 仍然会因为 ADL 而被搜索,因为参数的类型 std::string 位于命名空间 std 中)。

为避免这种情况发生,您可以将 swap 放在命名空间中,并使用限定名称(例如 mystuff::swap(a, b);)。