Как определить, какие заголовочные файлы включить?

13

Скажем, у меня есть ниже (очень простой) код.

#include <iostream>
int main() {
    std::cout << std::stoi("12");
}

Это прекрасно компилируется как на g ++, так и на clang; однако он не может быть скомпилирован в MSVC со следующей ошибкой:

ошибка C2039: «Stoi»: не является членом «STD»

ошибка C3861: «стои»: идентификатор не найден

Я знаю, что std::stoiэто часть <string>заголовка, который предположительно два бывших компилятора включают как часть, <iostream>а последний нет. Согласно стандарту C ++ [res.on.headers]

Заголовок C ++ может включать в себя другие заголовки C ++.

Что для меня в основном говорит о том, что все три компилятора верны.

Эта проблема возникла, когда один из моих студентов представил работу, которую ТА пометил как не компилируемую; Я конечно пошел и починил это. Однако я бы хотел предотвратить подобные инциденты в будущем. Итак, есть ли способ определить, какие файлы заголовков следует включить, если не учитывать компиляцию на трех разных компиляторах, которые нужно проверять каждый раз?

Единственный способ, который я могу придумать, - убедиться, что для каждого stdвызова функции существует соответствующее включение; но если у вас есть код длиной в тысячи строк, поиск по нему может быть утомительным. Есть ли более простой / лучший способ обеспечить совместимость с кросс-компилятором?

Пример с тремя компиляторами: https://godbolt.org/z/kJhS6U

ChrisMM
источник
6
Если вы помните, что std::stoiэто для обработки строк, вы можете догадаться, что <string>это будет хороший заголовок для включения. Или вы можете найти хорошую ссылку, которая скажет вам. И я рекомендую всегда явно включать файлы заголовков, чтобы вам не приходилось полагаться на поведение, не зависящее от переносимой реализации.
Какой-то программист чувак
3
Лучший способ - перейти к cppreference перед переходом на любую другую платформу. Там есть довольно подробные вещи.
Сиддхарт
1
Включите соответствующий заголовок в момент написания кода. То есть. в тот момент, когда вы пишете код, который содержит, std::stoiвы сразу же убедитесь, что #include <string>он присутствует.
Сандер Де
3
В общем случае это сложная проблема . Тем не менее, когда мы говорим об отсутствии стандартных библиотечных включений, нормальным способом действительно является проверка всех используемых вызовов / типов функций.
Макс
1
@ skratchi.at, учащимся говорят, что они могут использовать тот компилятор, который им нужен, при условии, что их код соответствует стандартам. Через 4 года это первый раз, когда это было проблемой.
ChrisMM

Ответы:

14

Есть ли более простой / лучший способ обеспечить совместимость с кросс-компилятором?

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

Когда вы пишете новый код, который использует стандартную функцию, например std::stoi, вставьте это имя в Google, перейдите к статье cppreference.com, а затем посмотрите вверху, чтобы увидеть, в каком заголовке он определен.

Затем включите это, если оно еще не включено. Работа выполнена!

(Вы можете использовать стандарт для этого, но это не так доступно.)

Не поддавайтесь искушению уволить все в пользу дешевых, непортативных хаков, как <bits/stdc++.h>!


тл; др: документация

Гонки легкости на орбите
источник
3
Чтобы быть справедливым, как только вы запомнили их все и больше не нуждались в
гонки на
5
@JosephWood: Если вы не знаете, к какому заголовку относится данная функция наизусть, скорее всего, вам стоит поискать эту функцию, чтобы в любом случае дважды проверить свои предположения, поэтому выяснение, к какому заголовку она принадлежит, даже не требует дополнительных затрат. время.
DevSolar
1
Как и @JosephWood, я также надеялся, что у тех, у кого больше опыта, будет лучший способ. Я знаю, какие заголовки включить для большинства функций STL, но надеялся, что есть более простой способ научить студентов, чем искать каждую функцию: P
ChrisMM
1
@ChrisMM есть такие инструменты, как include-what-you-use . Их правильность не может быть гарантирована (и действительно иногда требуется ручная работа), но это совсем не плохо.
причудливо
4
@ChrisMM Обучение ваших студентов обращению к документации невероятно, невероятно важно . Тысячи людей приходят на этот сайт каждый день, даже не подозревая, что они должны это делать. Использование документации является проще / лучше.
Гонки
-1

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

Вы можете использовать ReSharper в Visual Studio, которая способна организовать импорт (на самом деле VS без ReSharper не очень удобен). Если include отсутствует, он рекомендует добавить его, а если он устарел, строка с include будет показана более светлыми цветами.

Или вы можете использовать CLion (доступен для всех платформ), который также имеет эту возможность (на самом деле это тот же производитель JetBrains).

Существует также инструмент под названием include, который вы использовали , но его цель - воспользоваться преимуществами предварительного декларирования, я никогда не использовал его (лично - мой товарищ по команде сделал это для нашего проекта).

Марек Р
источник
clion не включает автоматически правильный заголовок, если другой заголовок уже включен, если работает (т.е. не будет предлагать строку здесь, если iostream уже включен) IIRC
RiaD