Search code examples
c++language-lawyernew-operatorinitializer-listtypeinfo

When to include headers for built-in types and operators?


When should one include headers for built-in types?

  • <new> for new (seems for sophisticated overloadings it is really needed); it can be just used.
  • (edit: wrong example (see answers)) <typeinfo> for std::type_info; it can be just acquired by using typeid operator
  • (edit: wrong example (see answers)) <initializer_list> for std::initizlizer_list; it is just result of auto l = {1, 2, 3}; or temporary in for (int i : {1, 2, 3}) {}
  • <cstddef>/<cstdio>/<cstring>/<ctime> for std::size_t; it can be given as result of operator sizeof val or sizeof(Type)
  • <cstddef> for std::nullptr_t; decltype(nullptr)
  • <cstddef> for std::ptrdiff_t; decltype(std::declval<int *>() - std::declval<int *>())
  • <tuple> for some functionality of structured bindings
  • maybe others

Are there cases when inclusion of corresponding headers is mandatory?


Solution

  • Strictly speaking, not all of your examples behave as you seem to expect. For instance

    [expr.typeid]

    6 If the header <typeinfo> is not included prior to a use of typeid, the program is ill-formed.

    [dcl.init.list]

    2 ... The template std​::​initializer_­list is not predefined; if the header <initializer_­list> is not included prior to a use of std​::​initializer_­list — even an implicit use in which the type is not named — the program is ill-formed.

    So there's two examples right off the bat. And sure, you can get by without including some headers, for instance

    using size_t    = decltype(sizeof(0));
    using nullptr_t = decltype(nullptr);
    

    But in general, the way to guarantee with complete certainty that we get well-defined results, is to include the proper header for standard types.