The program has undefined behavior because you use std::cout
without having any guarantee that it is initialized.
The standard streams like std::cout
are not automatically initialized and usable. Instead the header <iostream>
behaves as if it declared a global static storage duration variable of type std::ios_base::Init
. When a variable of this type is initialized, it will initialize the standard streams and make them usable.
The initialization of the static storage duration variable A<int>::b
is dynamic initialization, because the constructor of B
is not constexpr
and even if it was constexpr
still, because it calls a non-constexpr
operator<<
. And because it is a non-local variable instantiated from a template, it has unordered dynamic initialization, meaning that its initialization is unordered with any other dynamic initialization of non-local variables.
Because the initialization of A<int>::b
is unordered with initialization of <iostream>
's std::ios_base::Init
instance, it may happen prior to the initialization of std::cout
.
To assure that the streams are initialized when you need to use them before main
is entered, you need to initialize a std::ios_base::Init
instance yourself:
B(int v):val(v){
std::ios_base::Init _;
std::cout<< val << "\n";
}
Or better, avoid global variables with dynamic initialization before main
and instead use local static storage duration variables which are initialized at their first point of use from main
. See e.g. the Meyers' singleton pattern.
std::cout
is used. – Debbydebeecout
andcin
; you just need to#include <iostream>
as the very first line in the TU. It seems like CLANG has not used that(nifty counter) pattern; I don't know if it is a platform bug or not. But the recommended way of definingstatic
variables is Meyers' singleton. – Bribery