std.algorithm.fill accepts a range. All string types are dchar ranges. This is because they are all unicode. char is a UTF-8 code block wchar is a UTF-16 code module, and dchar is a UTF-32 code block. Multiple units of code constitute a code point, which is a symbol. For UTF-8, a code point can contain up to 6 code units. For UTF-16, this can be up to 2. For UTF-32, 1 code block is always 1 code point, so dchar always guaranteed to be a valid character. char and wchar alone are not guaranteed to be valid characters at all, and this is usually a mistake if you see an individual char or wchar . Multiple chars or wchars often need to be combined to make up one character. Thus, you cannot deal with chars or wchars individually. Therefore, if you repeat a string of any type using foreach, you should always specify its type as dchar .
foreach(dchar c; str) ...
If you did not specify dchar , then it will be any type of str character that invariably causes errors, unless str was a dchar array, because you end up with code blocks (pieces of characters) instead of code points (whole characters). Only dchars can be processed individually.
Because of this, all string types and character arrays are considered dchar ranges, regardless of what their actual element types are. So, when you call popFront on a line, it can go out much more than just one char or wchar . And if you call front , you may have to decode several chars or wchars to return dchar , which is the first character in the string. This means that you cannot treat char or wchar arrays as random access. The 4th character may be the 4th element, or it may be the 12th. And no matter what index it starts at, it can be several units of code for a long time, so you cannot just grab a random index in a char or wchar array and expect it to be valid. Thus, char and wchar arrays are not random access ranges. They are also not output ranges.
Think about it. Take, for example, the character '\U00010143' ( 𐅃 ). It has a code block length of 4 for UTF-8 and 2 for UTF-16. You cannot just fill in any random char or wchar array. If it is a char array, and its length is not a multiple of 4, then the last ( 𐅃 ) is not suitable. If it is a wchar array and its length is not a multiple of 2, then it will have the same problem. Thus, a function like fill in a char or wchar array does not actually work.
Now this will work just fine with the dchar array. Since the UTF-32 code is guaranteed to be a code point, each character in the dchar array is a single element, and it can be either a random access range or an output range. So, if you want to use a function like fill with arrays of characters, you need to use a dchar array. You can use std.conv.to to convert it to the type of character array you want after that, but you cannot directly populate a char or wchar array.
The char and wchar arrays do fine with algorithms that don't need output ranges or random access ranges, but they don't work with them. For them you need dchar arrays.