2

I'm trying to learn C++ and I'm using MS Visual Studio 2019. I have the code below:

#include <iostream>

int main()
{
    std::cout << pow(10, 2);
}

How is it possible to compile and run without error without including cmath? Inside the solution there is only one file with the above code.

izhang05
  • 744
  • 2
  • 11
  • 26
Liviu
  • 33
  • 6

2 Answers2

8

How is possible in C++ to use pow without include cmath library

By including another header that includes the <math.h> header.

There is no guarantee that standard library headers won't include other headers in general, nor that <iostream> won't include <cmath> in particular. Nor is there a guarantee that <iostream> will include that header, so this program may fail to compile when using another standard library implementation or another version of the same.

In concluson: Never rely on such transitive inclusion. Always directly include all of the headers whose declarations you depend on, unless the transitive include is explicitly doumented (for example, <ios> is guaranteed to include <iosfwd>). You cannot use successful compilation as proof that you have provided all of the required direct inclusions.

eerorika
  • 232,697
  • 12
  • 197
  • 326
4

Update: Concerned by a comment by @Pete Becker, I correct my answer to that:

Your code is, ill formed and by that invokes so called undefined behavior not implementation defined behavior.

However this conclusion is not completely safe, since we enter the part of language lawyering here.

Undefined behavior (UB) is defined as

behavior for which this International Standard imposes no requirements which usually means: Don't try to reason about this code and never use it.

The question is, does C++ specify requirements on your code i.e. is your code a well-formed program? Then this would be specified behavior (the usual behavior),unspecified behavior or even the qualification of that implementation defined behavior. But in in 20.5.2.2 Headers [using.headers] the C++ standard says

A translation unit shall include a header only outside of any declaration or definition, and shall include the header lexically before the first reference in that translation unit to any of the entities declared in that header. No diagnostic is required.

According to Difference between Undefined Behavior and Ill-formed, no diagnostic message required this would imply undefined behavior, even though it does not directly violate the 6.2 One-definition rule, which would have to be violated in your case to be a ill-formed program, but as the answer to the linked question already stated that this rule defaults to undefined behavior, if there is not exactly one definition, we have an ill formed program here.


Old part: Simple but unsatisfactory answer: So called implementation defined behavior. The Microsoft Visual C++ compiler and its headers are free to already include each other, probably MSVCs iostream header is already including cmath in an at least transitive way if not directly.

The fun begins if you try to compile the same code with gcc or clang. Sudden missing includes are the most common portable errors of my code at least.

If you actually include every header that the standard says it required i.e. contains the definitions of what you are using you get so called portable code, meaning code that will compile and do the same regardless of using MSVC/Visual Studio or gcc or clang or any other standard conformant compiler.

Superlokkus
  • 4,731
  • 1
  • 25
  • 57
  • As expected, the example does not compile using gcc (`pow` was not declared in this scope). I suspect clang reports the same. – Nelewout Apr 20 '20 at 14:24
  • 1
    Sometimes I have to fix my code exactly 2 times: After writing it on linux with gcc, I get an error by MSVC on windows for a missing include, and after fixing that, I got another missing include later when tring to compile it with clang on mac. – Superlokkus Apr 20 '20 at 14:26
  • I mostyl manage to avoid those problems by running my code through a CI tool, on various platforms/compilers. But yes, I definitely felt your pain! – Nelewout Apr 20 '20 at 14:28
  • @N.Wouda Thrust me, forgotten includes are no pain. The pains starts when one gets to things like undefined or implemention defined behaviour plus the nice standard phrase of "no diagnostics required". For example `std::array` iterators are very different between gcc/clang and MSVC. – Superlokkus Apr 20 '20 at 14:32
  • It's not implementation defined. It's specific to the implementation, but in standardese, "implementation defined" means that the standard doesn't say what happens, but the compiler must document its behavior. – Pete Becker Apr 20 '20 at 14:44
  • @Superlokkus -- concerting `std::array` iterators, are you saying that one or the other of those implementations does not do what the standard requires? Or are you saying that when you go outside of what the standard requires, they do different things? The former is a problem; the latter is, at best, carelessness. – Pete Becker Apr 20 '20 at 14:45
  • @PeteBecker So you are saying, according to standard, this is undefined behavior? – Superlokkus Apr 20 '20 at 14:56
  • @PeteBecker No I am not saying that those implementations are not standard conformant in that case. Accidental trying to use the same iterator for `std::array` and `std::array` is not carelessness, since it will break at compile time by a nice warning. All I am trying to say is that writing portable code is a non trivial problem. Especially in times of standard bugs and unspecified behavior. Maybe thats the rather class of "bug" we have here: Unspecified behavior. Do you concur? – Superlokkus Apr 20 '20 at 15:02
  • @PeteBecker Well I was going to change it to [defns.unspecified] as you suggested but since https://learn.microsoft.com/en-us/cpp/standard-library/iostream?view=vs-2019 is documenting which headers the iostream header includes, I assume we can find a transitive include note chain in this documentation and thats to only difference to [defns.impl.defined] I am aware of. – Superlokkus Apr 20 '20 at 15:11
  • @PeteBecker But I fear the biggest question is whenever this code is [defns.well.formed] or not. – Superlokkus Apr 20 '20 at 15:13
  • 1
    @Superlokkus -- no, not undefined behavior. Unspecified. This is **just** a point about technical terms; "implementation defined" is often used incorrectly to mean "up to the implementation", omitting the requirement for implementation-defined behavior that the implementation must document its behavior. – Pete Becker Apr 20 '20 at 17:41
  • @PeteBecker Do you mean [defns.unspecified] or just unspecified but not undefined? – Superlokkus Apr 20 '20 at 19:27