What does a typedef with three arguments mean?

Yes, most typedefs contain the alias name and the underlying type, but there's no requirement that the type be a single token:

typedef unsigned long long int ULLI;
//      \____________________/
//  Many tokens for underlying type

So whatever your code works under appears to have already a double complex type.

This type is actually part of the C standard, held in <complex.h> but the equivalent C++ <ccomplex>/<complex.h> header has now been replaced with <complex>, more suited to C++, so it would be more proper to include that and use the complex<double> type.

I believe, as of C++17, <ccomplex>/<complex.h> stopped holding any legacy C stuff and just started including other non-legacy headers from the C++ standard library.

And then, in C++20, they ditched it altogether. From (slightly paraphrased) C++20 [diff.cpp17.library], which details the differences:

Change: Remove vacuous C++ header files.

Rationale: Empty headers implied a false requirement to achieve C compatibility with the C++ headers.

Effect on original feature: A valid C++ 2017 program that performs a #include of <ccomplex> (amongst others) may fail to compile. To retain the same behavior, a #include of <ccomplex> can be replaced by a #include of <complex>.

complex is not a keyword in C++, and double complex is not a type . You are mixing up C++ with another language .

Instead you can use std::complex<double>, with or without a typedef.