```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 a safe approach
        
        # Compute 2**i safely: if i is large, 2**i can be huge
        # Instead, we can check if base * (2**i) >= cap without computing the full power
        # We can do this by checking if 2**i >= cap / base
        # Since cap and base are floats, cap / base is a float
        # But 2**i for large i can overflow when converted to float
        
        # Alternative: compute iteratively, multiplying by 2 each time, but stop when value >= cap
        # Start with current = base, and for each i, current = base * 2**i
        # We can maintain current as a float, but if it exceeds cap, we just use cap
        
        # Let's use an iterative approach to avoid overflow
        # For i=0, value = base
        # For i=1, value = base * 2
        # For i=2, value = base * 4
        # ...
        # We can compute iteratively: start with val = base, then multiply by 2 each step
        # But we need to handle the case where val might overflow
        
        # Actually, let's compute iteratively:
        # val = base
        # for i in range(attempts):
        #   result.append(min(cap, val))
        #   val *= 2
        #   if val > cap:
        #       # Once val exceeds cap, all subsequent values will be cap
        #       # But we need to be careful: val might overflow
        
        # Let's use this iterative approach with overflow protection
        val = base
        for i in range(attempts):
            if val >= cap:
                result.append(cap)
            else:
                result.append(val)
            val *= 2
            # If val becomes too large, it will be >= cap, so we can break early
            # But we still need to fill the remaining entries with cap
            if val > cap:
                # Fill remaining with cap
                for j in range(i + 1, attempts):
                    result.append(cap)
                break
    
    return result
```