There are different value types in C++ types. To take the address of something with &, it needs to be an l-value. Temporary variables, like what enviroment->getDirectionalLight()->getAmbientIntensity() returns, are r-values, which means you can't take their address.
Think of it like this: Where does the float returned by enviroment->getDirectionalLight()->getAmbientIntensity() live? Where is its home? Answer: it doesn't have one. It's "homeless." It's just a temporary float that's being returned by a function, and so it never gets a "home" assigned to it. If something doesn't have a home, how can you take its address? You can't. The address points to "home," and thus if you could take its address it would have a home in the first place!
Why is this important? Well, look at that function. It's taking a pointer to a float. That means the function has the power and ability to change that float. But that float is temporarily existing. You can't change a temporary like that. If you could do that, then why not be able to do int* x = &2; *x = 3; (uh oh... did we just change 2 to now be 3? that's (one reason) why something like this isn't legal).
Note that this is a pretty high level explanation. You could get super technical and say that the temporary float does (or even better: might) have a home, but I don't really want to get into those details too much. If you want to view it like this, just think of it as a super temporary home that has some special rules you can't mess with. Kind of like a guest-home. The float is just a guest at the home, it doesn't "own" the home. You can't go in and start changing things in a home you don't own. Not legally, at least.