Hi, so to work with complex numbers C++ has to store two real numbers (double precision floating point) to represent one complex number. This means twice the memory usage, which is wasteful if one is doing a calculation where the imaginary parts are always zero (such as DMRG with a real-valued Hamiltonian).
In terms of time costs, contracting complex tensors is more costly than contracting real tensors. To illustrate why, if you think about multiplying two real matrices of size NxN, the complexity is N^3. If you then think about representing a complex matrix as a real matrix of size 2N, then the complexity for multiplying the complex matrices will be 8N^3, so a factor of 8 slower. Of course in an optimized BLAS for complex matrices, there are some extra efficiencies, but in general there's always some extra cost for handling complex numbers.
So the strategy in ITensor is to avoid dealing with complex numbers at all whenever possible. This is done by having separate storage types for real and complex tensors. The nice thing is that these storage types can be mixed together e.g. one could make an array of ITensors with some having real and some having complex storage. When contracting two real ITensors you get maximum efficiency. When the contraction involves a complex tensor, there is an extra cost for dealing with complex numbers.