One of the headers in your compiler's standard library is internally including a header that defines std::thread
(in your case, <mutex>
is including this).
The C++ standard only guarantees which definitions will be visible for any #include
d header -- but it does not control or prevent the implementation from either intentionally or unintentionally making other definitions visible from that header.
Often this happens because the headers in your standard library implementation have been written such that they include other internal headers that bring these definitions transitively (such as <mutex>
being written to include <internal/thread.hpp>
or something).
Relying on this transitive inclusion is an extremely bad practice, and massively reduces the portability of a given program. This can make it complicated to move between different platforms, standard library implementations, and even different versions of the same compiler if they updated the internal inclusion ordering.
Note: It's important to be aware that just because a standard type may have a dependency to another standard type defined in another header, it does not guarantee that this header will be transitively included by the standard library unless the C++ standard actually dictates this (which is very rarely done).
For example, the exception std::logic_error
is defined in <stdexcept>
, and derives std::exception
defined in <exception>
; however #include <stdexcept>
is not defined to introduce the symbol std::exception
. Some or most standard library implementations may do this; but it is equally legal for a standard library to internally do indirection like the following instead to prevent this from occurring:
<impl/exception.hpp>
namespace std {
namespace __impl {
class exception { ... };
} // namespace __impl
} // namespace std
<exception>
#include <impl/exception.hpp>
namespace std {
using __impl::exception;
} // namespace std
<impl/stdexcept.hpp>
#include <impl/exception.hpp>
namespace std {
namespace __impl {
class logic_error : public exception { ... }
/* ... other error types ... */
} // namespace __impl
} // namespace std
<stexcept>
#include <impl/stdexcept.hpp>
namespace std {
// defines 'std::logic_error', and derives 'std::exception', but
// does not define the symbol 'std::exception' (instead, hides it
// under std::__impl::exception)
using __impl::logic_error;
/* ... other error types ... */
} // namespace std
From the above example you can see that #include <stdexcept>
would define the symbol std::logic_error
but not std::exception
, even though the two types are closely related.
As a result, it's always a good idea to follow include-what-you-use (IWYU) practices wherever possible, even if it appears as though you may be including a redundant header. Otherwise you may be fixing yourself to your current setup, and introducing more complications for future portability (even if it's just for upgrading your compiler)