14

Say I have the below (very simple) code.

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

This compiles fine on both g++ and clang; however, it fails to compile on MSVC with the following error:

error C2039: 'stoi': is not a member of 'std'

error C3861: 'stoi': identifier not found

I know that std::stoi is part of the <string> header, which presumably the two former compilers include as part of <iostream> and the latter does not. According to the C++ standard [res.on.headers]

A C++ header may include other C++ headers.

Which, to me, basically says that all three compilers are correct.

This issue arose when one of my students submitted work, which the TA marked as not compiling; I of course went and fixed it. However, I would like to prevent future incidents like this. So, is there a way to determine which header files should be included, short of compiling on three different compilers to check every time?

The only way I can think of is to ensure that for every std function call, an appropriate include exists; but if you have existing code which is thousands of lines long, this may be tedious to search through. Is there an easier/better way to ensure cross-compiler compatibility?

Example with the three compilers: https://godbolt.org/z/kJhS6U

Community
  • 1
  • 1
ChrisMM
  • 8,448
  • 13
  • 29
  • 48
  • 6
    If you remember that `std::stoi` is for handling *strings* you could guess that `` would be a good header to include. Or you could search for [a good reference](https://en.cppreference.com/w/cpp/string/basic_string/stol) which will tell you. And I recommend that you always explicitly include the header files, so you don't have to rely on non-portable implementation specific behavior. – Some programmer dude Nov 27 '19 at 12:31
  • 3
    Best way is to go to [cppreference](https://en.cppreference.com/w/cpp/string/basic_string/stol) before going to any other platform. They have pretty detailed stuff there. – Siddharth Nov 27 '19 at 12:33
  • 1
    Include the appropriate header the moment you write the code. Ie. the moment you write code that contains, [`std::stoi`](https://en.cppreference.com/w/cpp/string/basic_string/stol), you immediately make sure `#include ` is present as well. – Sander De Dycker Nov 27 '19 at 12:33
  • 3
    In the general case this is a [difficult problem](https://github.com/include-what-you-use/include-what-you-use). However, when we are talking about missing standard library includes, the normal way would indeed be to examine all function calls/types used. – Max Langhof Nov 27 '19 at 12:33
  • The usual way is to read the documentation for each of the standard types or functions you are using. The standard specifies which header (or headers) are required to define each standard type or function. Some reference sites (e.g. cppreference.com) do a pretty good job of documenting those requirements too, if you don't want to hunt through the standard. Include all the headers that the standard says are required by your code, even if your compiler allows you to get away with not including all of them. – Peter Nov 27 '19 at 12:34
  • I'm currently in the process of learning C++ and have had similar issues finding my headers as well. As far as I can tell now, there is no way to *determine* a header, my first thought was to [auto-include needed C++ headers](https://stackoverflow.com/questions/33659794/auto-include-needed-c-headers-ide) for your students, but that doesn't seem to be viable. As mentioned by @Siddharth just to check out cppreference *(or just plain Google since the first result will most likely be cppreference)*. Over time they will gain enough experience to know headers for certain functions. – AlexG Nov 27 '19 at 12:36
  • if you are the teacher, you should define for which compiler it should compile. OR if you want more freedom for your students, let them document, which compiler they use. – skratchi.at Nov 27 '19 at 12:54
  • 1
    @skratchi.at, students are told they can use whichever compiler they want, so long as their code is standard-conforming. After 4 years, this is the first time this has ever been an issue. – ChrisMM Nov 27 '19 at 12:57
  • That's a decent rule, and that you've run into this issue is actually a good thing. It's a great lesson to learn, in terms of how even conformant toolchains can produce different results. It's not a problem, just something useful to learn from. Thinking about it, if teachers were reeeeeally clever it might even be worth deliberately sneaking this into a course while making it look like an accident :P – Lightness Races in Orbit Nov 27 '19 at 13:35
  • A few weeks ago, I went over the `std::tolower` issue that [g++ has](https://stackoverflow.com/questions/7131858/stdtransform-and-toupper-no-matching-function) when include `` for `std::transform`, because a student found that `std::tolower` apparently wasn't defined in g++. These are interesting cases that I find fascinating; but until you run across them, you don't ever really think about it. – ChrisMM Nov 27 '19 at 13:50

2 Answers2

15

Is there an easier/better way to ensure cross-compiler compatibility?

This is always going to be a bit of a chore if you have a huge codebase and haven't been doing this so far, but once you've gone through fixing your includes, you can stick to a simple procedure:

When you write new code that uses a standard feature, like std::stoi, plug that name into Google, go to the cppreference.com article for it, then look at the top to see which header it's defined in.

Then include that, if it's not already included. Job done!

(You could use the standard for this, but that's not as accessible.)

Do not be tempted to sack it all off in favour of cheap, unportable hacks like <bits/stdc++.h>!


tl;dr: documentation

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • I'm encouraged by your answer as this has been my mode of operation. Every time I do it, it feels a bit brute forceish/not sophisticated and I'm always thinking "I bet the pros like that Lightness SO contributor has a super slick way of doing this." – Joseph Wood Nov 27 '19 at 12:40
  • 3
    To be fair, once you've effectively memorised them all and don't need to look it up any more, that feels pretty slick – Lightness Races in Orbit Nov 27 '19 at 12:41
  • 5
    @JosephWood: If you don't know which header a given function is by rote, chances are you *should* look the function up to double-check your assumptions on it anyway, so finding out which header it belongs to doesn't even take extra time. – DevSolar Nov 27 '19 at 12:44
  • 1
    Like @JosephWood, I was also hoping those with more experience had a better way. I know which headers to include for most STL functions, but was hoping there's an easier way to teach students than to look up every function :P – ChrisMM Nov 27 '19 at 12:46
  • @ChrisMM, indeed. Although I enjoy reading the docs as I always come away learning more than I originally intended, my hunch was that there was a tool akin to linux's [ldd](https://en.wikipedia.org/wiki/Ldd_(Unix)). – Joseph Wood Nov 27 '19 at 12:48
  • 1
    @ChrisMM there are tools like [include-what-you-use](https://include-what-you-use.org/). Their correctness cannot be guaranteed (and indeed sometimes manual work is necessary) but it's not bad at all. – freakish Nov 27 '19 at 12:49
  • I did both write that, and link to that, but thanks @Marek :) – Lightness Races in Orbit Nov 27 '19 at 13:00
  • 4
    @ChrisMM Teaching your students to refer to the documentation is _incredibly, incredibly important_. Thousands stream onto this site every day with no earthly idea that they should do it. Using the documentation _is_ the easier/better way. – Lightness Races in Orbit Nov 27 '19 at 13:01
  • @LightnessRaceswithMonica, I completely agree. I tell them to refer to cppreference and cplusplus. There's only so many times you can tell students to RTFM though :P – ChrisMM Nov 27 '19 at 13:31
-1

Besides reviewing documentation and doing that manually (painful and time consuming) you can use some tools which can do that for you.

You can use ReSharper in Visual Studio which is capable to organize imports (in fact VS without ReSharper is not very usable). If include is missing it recommends to add it and if it is obsolete line with include is shown in more pale colors.

Or you can use CLion (available for all platforms) which also has this capability (in fact this is the same manufacture JetBrains).

There is also tool called include what you used, but its aim is take advantages of forward declaration, I never used that (personally - my team mate did that for our project).

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • clion doesn't autoinclude of correct header when other header is already included if works(ie. will not suggest string here if iostream is already included) IIRC – RiaD Nov 27 '19 at 23:13