```python
def retry_delays(attempts, base, cap):
    if isinstance(attempts, bool) or not isinstance(attempts, int):
        raise TypeError("attempts must be a non-negative integer")
    if attempts < 0:
        raise ValueError("attempts must be non-negative")
    if base < 0:
        raise ValueError("base must be non-negative")
    if cap < 0:
        raise ValueError("cap must be non-negative")
    
    result = []
    for i in range(attempts):
        # Compute base * 2**i without causing overflow by checking if 2**i exceeds cap/base
        # If base == 0, then base * 2**i == 0, so min(cap, 0) = 0
        if base == 0:
            result.append(0.0)
            continue
        # Check if 2**i would cause base * 2**i to exceed cap
        # We can avoid computing huge powers by comparing incrementally
        # If base * 2**i >= cap, then min(cap, base * 2**i) = cap
        # We need to check if 2**i >= cap / base
        # But cap/base might not be an integer, so we use float comparison carefully
        # To avoid overflow, we can check if i is large enough that 2**i > cap / base
        # Since base > 0, cap / base is finite. If 2**i > cap / base, then base * 2**i > cap, so result is cap.
        # We can compute threshold = cap / base. If 2**i >= threshold, result is cap.
        # But 2**i can be huge. Instead, we can check if i >= log2(cap / base) approximately.
        # Alternatively, we can compute iteratively: start with val = base, multiply by 2 each step, but cap the value.
        # This avoids computing huge powers directly.
        pass
    
    # Better approach: compute iteratively, multiplying by 2 each step, but cap at cap.
    # Start with current = base
    # For each i, result[i] = min(cap, current)
    # Then current *= 2 for next iteration, but if current already >= cap, it stays capped.
    # This avoids computing 2**i directly and avoids overflow.
    
    result = []
    current = base
    for i in range(attempts):
        if current >= cap:
            result.append(cap)
        else:
            result.append(current)
            current *= 2
            # If current becomes very large, it might overflow, but since we cap at cap,
            # once current >= cap, we just append cap and don't need to multiply further.
            # However, if cap is 0, then base must be 0 (since base >= 0 and cap >= 0, and if cap=0, base*2**i >= 0, min(0, ...) = 0).
            # Let's handle cap == 0 separately.
    
    # Handle cap == 0 case: all results are 0
    if cap == 0:
        return [0.0] * attempts
    
    # Re-implement with iterative approach to avoid overflow
    result = []
    current = base
    for i in range(attempts):
        if current >= cap:
            result.append(cap)
        else:
            result.append(current)
            current *= 2
            # If current exceeds cap, next iteration will append cap
            # But current could become huge if cap is large and base is small.
            # However, once current >= cap, we stop multiplying (we just append cap).
            # So current never exceeds cap significantly.
            # Actually, current could exceed cap by a factor of 2, but that's fine.
            # The issue is when base * 2**i is computed as a float, which can overflow.
            # By using iterative multiplication and capping, we avoid computing huge powers.
    
    return result
```