2015-07-12 3 views
-5

Я просто работал над типами C++, когда я просто думал попробовать следующую программу.Строка преобразования неявного типа C++ -> int?

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; 
    } 

Я не ожидал, что это заменит струны, но это так! Почему это работает? Хотя компилятор поднимает предупреждения, это не ошибка!

+1

Чтобы убедиться, что ваша программа действительно делает то, что, по вашему мнению, она делает, сделайте свою функцию 'swap' напечатать сообщение. –

+0

Чтобы улучшить свой вопрос, разместите фактический код, который дает проблему. Вы, очевидно, опустили некоторые строки, возможно, думая, что они неважны. –

+0

благодарит за отзыв. Это было действительно полезно.Я не ожидал, что встроенная функция swap будет вызвана. Я сделал это для печати сообщения, как это было предложено @ n.m. и это доказало, что мой обмен не был вызван. Я использовал «using namespace std», и это преступник здесь. Большое спасибо! В следующий раз будет включать полный код. Извините за это –

ответ

1
// 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; 
} 

Это не вызов вашей функции обмена. Пространства имен - это своего рода интерфейсы, поэтому, когда объявляемые свободные функции находятся в одном и том же пространстве имен, как и типы данных, на которых они работают, тогда их вызов без надлежащей квалификации пространства имен будет работать.

Это называется поиском зависимых от аргументов имен или ADL.

Поэтому, когда вы вызываете функцию swap на std::string, она также будет искать кандидатов в пространстве имен std. И так как есть std::swap, который может быть применен к строкам и никому другому кандидату в вашем глобальном пространстве имен (поскольку ваш своп работает только с целыми числами), он будет использовать его для вызова.


Как я показал выше, вы можете сделать свою функцию производят вывод отладки или переименовать его легко проверить, что это не ваша функция, которая называется.

В качестве примечания стороны: предположим, что существует какое-то неявное преобразование из строки в int. Тогда вы получите два временных. Тогда ваша функция подкачки будет вызвана (не в действительности, начиная с binding non const references to temporaries isn't allowed), и эти целые числа обмениваются. А потом? Это не повлияет на исходные строки.


Наконец, я бы не стал считать этот код переносимым. Он компилируется только в том случае, если заголовочная строка или iostream включает заголовок алгоритма, а один из этих трех предоставляет специализацию std :: swap для строк. Но поскольку это не гарантируется стандартом, этот код будет надежно работать только при включении алгоритма.

+0

спасибо @ Daniel. Это был очень информативный пост! –

2

Ваша программа не компилируется. Я предполагаю, что вы на самом деле были следующие строки, но не размещать их:

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

Существует стандартный шаблон std::swap. Хотя это находится в #include <algorithm>, любой заголовок может содержать любой другой заголовок. Поэтому, даже если вы не включили его конкретно, оно, возможно, все равно включилось.

Поэтому, когда вы звоните в неквалифицированный swap, оба ваших swap и std::swap включены в разрешение перегрузки. (Даже если у вас не было using namespace std;, пространство имен std по-прежнему выполняется из-за ADL, поскольку аргументы имеют тип std::string, который находится в пространстве имен std).

Чтобы избежать этого, вы можете поместить свой swap в именованное пространство имен и использовать квалифицированное имя (например, mystuff::swap(a, b);).