Como determinar quais arquivos de cabeçalho incluir?

13

Digamos que eu tenho o código abaixo (muito simples).

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

Isso compila bem no g ++ e no clang; no entanto, ele falha ao compilar no MSVC com o seguinte erro:

erro C2039: 'stoi': não é membro de 'std'

erro C3861: 'stoi': identificador não encontrado

Eu sei que isso std::stoifaz parte do <string>cabeçalho, o que provavelmente os dois ex-compiladores incluem como parte <iostream>e o último não. De acordo com o padrão C ++ [res.on.headers]

Um cabeçalho C ++ pode incluir outros cabeçalhos C ++.

O que, para mim, basicamente diz que todos os três compiladores estão corretos.

Esse problema surgiu quando um dos meus alunos enviou um trabalho que o AT marcou como não compilando; Claro que fui e consertei. No entanto, gostaria de evitar futuros incidentes como esse. Portanto, existe uma maneira de determinar quais arquivos de cabeçalho devem ser incluídos, com exceção da compilação em três compiladores diferentes para verificar sempre?

A única maneira de pensar é garantir que, para cada stdchamada de função, exista uma inclusão apropriada; mas se você tiver um código existente com milhares de linhas, pode ser entediante pesquisar. Existe uma maneira mais fácil / melhor de garantir a compatibilidade entre compiladores?

Exemplo com os três compiladores: https://godbolt.org/z/kJhS6U

ChrisMM
fonte
6
Se você se lembra que std::stoié para lidar com seqüências de caracteres, você pode adivinhar que <string>seria um bom cabeçalho para incluir. Ou você pode procurar uma boa referência que lhe dirá. E eu recomendo que você sempre inclua explicitamente os arquivos de cabeçalho, para que não precise confiar no comportamento específico da implementação não portátil.
Algum programador
3
A melhor maneira é acessar a cppreference antes de acessar qualquer outra plataforma. Eles têm coisas bem detalhadas lá.
Siddharth
11
Inclua o cabeçalho apropriado no momento em que você escrever o código. Ou seja. No momento em que você escreve o código que contém std::stoi, você imediatamente se certifica de que também #include <string>está presente.
Sander De Dycker 27/11/19
3
No caso geral, este é um problema difícil . No entanto, quando estamos falando sobre a inclusão de bibliotecas padrão ausentes, a maneira normal seria de fato examinar todas as chamadas / tipos de função usados.
precisa
11
@ skratchi.at, é dito aos alunos que podem usar o compilador que quiserem, desde que o código deles esteja em conformidade com o padrão. Após 4 anos, é a primeira vez que isso é um problema.
ChrisMM

Respostas:

14

Existe uma maneira mais fácil / melhor de garantir a compatibilidade entre compiladores?

Isso sempre será um pouco complicado se você tiver uma base de código enorme e ainda não o fez até agora, mas depois de corrigir suas inclusões, você pode seguir um procedimento simples:

Quando você escreve um novo código que usa um recurso padrão std::stoi, conecte esse nome ao Google, vá para o artigo cppreference.com e veja o topo para ver em qual cabeçalho está definido.

Em seguida, inclua isso, se ainda não estiver incluído. Tarefa concluída!

(Você pode usar o padrão para isso, mas não é tão acessível.)

Não fique tentado a demitir tudo em favor de hacks baratos e não portáveis como <bits/stdc++.h>!


tl; dr: documentação

Raças de leveza em órbita
fonte
3
Para ser justo, uma vez que você efetivamente memorizado-los todos e não precisa procurá-lo mais, que se sente muito escorregadio
Leveza raças em órbita
5
@ JosephphWood: Se você não sabe em qual cabeçalho uma determinada função é rotineira, é provável que você deva procurar a função para verificar suas suposições de qualquer maneira, portanto, descobrir a qual cabeçalho pertence nem precisa ser extra. Tempo.
DevSolar 27/11/19
11
Como @ JosephphWood, eu também esperava que aqueles com mais experiência tivessem uma maneira melhor. Eu sei que os cabeçalhos para incluir para a maioria das funções STL, mas estava esperando há uma maneira mais fácil para os alunos ensinar do que olhar para cima cada função: P
ChrisMM
11
@ChrisMM, existem ferramentas como incluir o que você usa . Sua correção não pode ser garantida (e, de fato, às vezes é necessário trabalho manual), mas não é nada ruim.
freakish
4
@ChrisMM Ensinar seus alunos a consultar a documentação é incrivelmente, incrivelmente importante . Milhares de pessoas acessam este site todos os dias, sem a menor idéia de que deveriam fazê-lo. Usar a documentação é a maneira mais fácil / melhor.
Lightness Races in Orbit -
-1

Além de revisar a documentação e fazer isso manualmente (doloroso e demorado), você pode usar algumas ferramentas que podem fazer isso por você.

Você pode usar o ReSharper no Visual Studio, capaz de organizar importações (na verdade, o VS sem o ReSharper não é muito utilizável). Se o include estiver ausente, recomenda-se adicioná-lo e se for obsoleto, a linha com o include é mostrada em cores mais claras.

Ou você pode usar o CLion (disponível para todas as plataformas) que também possui esse recurso (na verdade, esse é o mesmo JetBrains de fabricação).

Também existe uma ferramenta chamada include, o que você usou , mas seu objetivo é aproveitar as vantagens da declaração direta, nunca usei isso (pessoalmente - meu companheiro de equipe fez isso no nosso projeto).

Marek R
fonte
clion não inclui automaticamente o cabeçalho correto quando outro cabeçalho já estiver incluído se funcionar (ou seja, não sugerirá uma string aqui se o iostream já estiver incluído)
IIRC