As already mentioned in comments above, std::array is an aggregate type, so you are not calling a constructor but actually initializing a data member.
The code you point at in the question allows creation of std::array without stating array's type and size. This is done, with deduction guides, as seen in the code below.
Here is how it may look if you implement it by yourself:
template<typename T, std::size_t SIZE>
struct MyArray {
T arr[SIZE];
};
// MyArray deduction guides:
// similar code was added to std::array in C++17 to allow the
// creation of a2 below, without providing template arguments
template <class _First, class... _Rest>
MyArray(_First, _Rest...) -> MyArray<_First, 1 + sizeof...(_Rest)>;
int main() {
MyArray<int, 5> a1 = {1, 2, 3}; // since C++11
MyArray a2 {1, 2, 3}; // deduced to MyArray<int, 3>, since C++17
// creation of a2 is based on the deduction guides above
}
The code above ignores the case of sending different types to MyArray, like this:
MyArray a2 {1, 2.0, 3}; // still deduced to MyArray<int, 3> with our code
There are several options to treat the above: decide that the type of the array is based on the type of the first value (as we actually do in our naive implementation), decide that the type would be based on the common_type of the values, or disallow such initialization. The C++ standard decided to disallow it, so there is a need to check that all types are the same and raise compilation error if not, e.g. using static_assert. As done in the original code posted, using the _Enforce_same struct.
The initialization of the inner data member is based on aggregate initialization, values sent to a struct are passed into its fields like in the examples below:
struct A {
int a;
};
struct B {
int a, b;
};
struct C {
int a[5];
};
int main {
A a = {1}; // goes to a.a
B b = {1, 2}; // goes to b.a and b.b
C c = {1, 2, 2}; // goes into the array c.a
}
std::arrayis an aggregate type, that means it doesn't have a user-provided constructor