TTL IS eviction policy. You just store a timestamp along the value. When you access it, you check the timestamp and if it is stale, you delete it and return not found error(or whatever not found should return). And you have a simple bg worker that scans the cache periodically and deletes these stale entries to free up the memory.
This is the basis for all caches. You can add cost on top of this as yet another eviction policy but that only adds another worker to scan the cache for items to purge and you have to store the cost along with the entry so you are increasing the each entry by at least 4 bytes, if we're talking uint32. Not to mention that for this eviction policy, you need sorted cache because you need to know where the cut off for cost is.
Walking the entire cache to purge expired TTL entries is one thing, but keeping ordered cache is a whole another thing.