Ошибка компоновщика C++

У меня была такая функция, которой не было в классе:

// Gets the maximum number of tracks displayable
const utils::uint32 GetConstMaxSystemRange()
{
    return constMaxSystemNumber - constMinSystemNumber + 1;
}

Он отлично компилировался в VS2005, но потом я получал ошибки компоновщика для каждого файла после первого, который его включил, хотя я использовал Compile Guards. Я догадывался, что окружил его таким классом:

class CDSLimitsAccess
{
public:
    // Gets the maximum number of tracks displayable
    static const utils::uint32 GetConstMaxSystemRange()
    {
        return constMaxSystemNumber - constMinSystemNumber + 1;
    }

protected:
    CDSLimitsAccess(){}
};

И бац! Фиксированный.

Вопрос: ПОЧЕМУ?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
498
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Включить охранники только защищают эту функцию от включения в одну и ту же единицу перевода дважды. Но это не защитит эту функцию от повторного включения во всю программу.

Поскольку функция не является встроенной, она нарушает правило одного определения, если встречается более одного раза во всей программе. Сделайте его встроенным, чтобы решить проблему, или поместите определение в файл реализации, поместив только его объявление в заголовок.

// Gets the maximum number of tracks displayable. possible fix:
inline utils::uint32 GetConstMaxSystemRange() {
    return constMaxSystemNumber - constMinSystemNumber + 1;
}

Кстати, лучше не ставить const во встроенное возвращаемое значение. Их временные элементы не могут быть определены с помощью const / volatile. Но это тоже не обязательно: вы все равно не можете их изменить. Насколько я знаю, это игнорируется. Но это никогда не подействует.

Я получаю новую ошибку компоновщика при компиляции с определением вне заголовка, так как что-то ниже по списку не может его найти. Встраивание (которое я должен был сделать в любом случае) исправил его. Спасибо! Однако не является ли встраивание частично решением компилятора и, следовательно, потенциально ненадежным в качестве решения?

deworde 12.01.2009 17:43

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

Johannes Schaub - litb 12.01.2009 22:50

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

Johannes Schaub - litb 12.01.2009 22:53

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

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

Вы можете поместить его в безымянное пространство имен или добавить статический объект перед ним, чтобы он стал локальным для единицы перевода. Однако это неправильный способ исправить это - просто включите объявление в заголовок и поместите реализацию в файл, и все будет в порядке.

Другие вопросы по теме