Почему я не могу включить стандартную библиотеку алгоритмов после определения эпсилон в C++?

Когда я включаю библиотеку алгоритмов перед определением эпсилон, компилируется следующий код:

#include <iostream>
#include <algorithm>

#define epsilon 0.00001

int main() {
    std::cout << epsilon; 
    return 0;
}

Когда я переключаю их, это не так:

#include <iostream>

#define epsilon 0.00001

#include <algorithm>

int main() {
    std::cout << epsilon; 
    return 0;
}

Это дает следующую ошибку 19 раз:

epsilon_algorithm.cpp:3:17: error: expected unqualified-id before numeric constant
    3 | #define epsilon 0.00001
      |

На http://www.cplusplus.com/reference/algorithm/ и https://en.cppreference.com/w/cpp/algorithm нет упоминания о чем-либо с именем ' эпсилон». Я знаю, что могу избежать этой проблемы, просто всегда включая ‹алгоритм› перед определением эпсилон. Я хочу знать, что вызывает эту ошибку, чтобы расширить мое понимание C++ и предотвратить подобные ошибки в будущем.

Я компилирую с помощью MinGW (32-разрядная версия, установленная несколько недель назад) в обновленной среде Windows 10 (64-разрядная версия).


person rvvermeulen    schedule 15.07.2020    source источник
comment
вот эпсилон   -  person user253751    schedule 15.07.2020
comment
Не используйте #define для констант. Вместо этого следует использовать inline constexpr auto epsilon = 0.00001; или что-то подобное. Скорее всего, ‹алгоритм› включает в себя ‹лимиты› и в них действительно есть epsilon.   -  person NathanOliver    schedule 15.07.2020


Ответы (1)


Заголовки стандартных библиотек могут включать любые другие заголовки стандартных библиотек.

Возможно, что <algorithm> включает <limits> и существует std::numeric_limits::epsilon(). И, конечно же, макросы игнорируют пространства имен и классы, поэтому он попытается объявить функцию с именем 0.00001.

Не используйте макросы. Используйте константы С++:

constexpr double epsilon = 0.00001;

И если вам абсолютно необходимы макросы, всегда определяйте их после всех включений. Если вы определите их заранее, ваш код станет очень хрупким. Любое изменение этих заголовков в будущем может привести к тому, что ваш код будет содержать загадочные ошибки компилятора.
Не определяйте макросы в файлах заголовков по той же причине.
Предпочтительнее очень локализованные макросы, когда это возможно - определите их там, где это необходимо, и #undef после того, как вы закончите. Таким образом, они не будут просачиваться наружу (хотя вы все равно можете непреднамеренно переопределить существующий макрос).

person Yksisarvinen    schedule 15.07.2020