Почему iostream определяет функцию пресса и как я могу ее остановить? - PullRequest
9 голосов
/ 15 марта 2012

Следующий код c ++ не компилируется:

int main() {
  double a = abs(5.1);
  return 0;
}

Жалуется, что abs не определено, конечно. Но следующее компилируется:

#include <iostream>

int main() {
  std::cout << abs(5.1) << std::endl;
  std::cout << abs(-5.1) << std::endl;
  return 0;
}

Выводит две 5 (не 5.1). Это плохо по многим причинам. Во-первых, abs - это такая естественная и распространенная функция, что я использую ее все время, но часть int почти никогда не возвращается. Во-вторых, мне (или людям, использующим мой код) слишком легко просто написать abs и не заметить, что он компилируется, но делает не то, потому что я (они) действительно хорошо пропускаю предупреждения. В-третьих, я просто не понимаю, почему iostream все равно не определяет функцию abs. В-четвертых, я действительно не понимаю, почему он входит в глобальное пространство имен.

Можно ли каким-то образом предотвратить попадание этой нежелательной функции abs в мое глобальное пространство имен?

Если это имеет значение, я использую

gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.6)

Ответы [ 3 ]

11 голосов
/ 15 марта 2012

Скорее всего, iostream включает stdlib.h для выполнения части своей работы.Это версия C заголовка, которая объявляет abs для int только в глобальном пространстве имен (в C вы должны были использовать fabs для double значений).

Я не в курселюбого конкретного способа не допустить включения abs таким образом, но я знаю, что g ++ 4.5 намного лучше, если не включать лишние вещи, вводимые базовыми включениями, такими как iostream и string.

Также может быть возможно получить предупреждение о том, что двойник усекается до целого (РЕДАКТИРОВАТЬ: да, используйте -Wconversion для предупреждения).

4 голосов
/ 15 марта 2012

В C, включая один стандартный заголовок, было , а не разрешено вести себя так же, как и любой другой стандартный заголовок.Это позволило избежать проблемы, с которой вы сталкиваетесь, при значительных затратах на реализацию трудностей.

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

К сожалению, я не думаю, что есть простой способ справиться с этим.Хотя довольно просто представить, что <iostream> не зависит от <stdlib.h>, гораздо проще понять, как ему могут понадобиться / нужны определения таких вещей, как ios_base.Потребовалось бы немного дополнительной работы, чтобы определить вещи, чтобы запретить первое, допуская второе.

Я должен отметить, однако, что со временем ситуация, кажется, немного улучшается.Десять лет назад было довольно распространено получать практически все стандартные заголовки, включая почти любой из них.Хотя большинство из них по-прежнему включают по крайней мере несколько из них, которые не являются строго обязательными, они обычно намного ближе к каждому, определяя только то, что требуется.

1 голос
/ 15 марта 2012

Если это постоянная проблема с обслуживанием, почему бы не добавить небольшой код в начале программы, который специально проверяет наличие проблемы abs()?

// test if abs() is defined incorrectly, as would happen if <stdlib.h> were
// included by <iostream>.  abs() it should return a float/double, not an int
// (put suggestions here how to fix problem)
if (abs(-5.1) == 5)
{
     std::cerr << "Invalid build:  abs() defined improperly, ..." << std::endl;
     return 2;  // exit program by returning from main
}

Это сделает ее намного труднеепредупреждения должны быть пропущены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...