I think you're misinterpreting the intent of the function based index here.
It is for the case where we want to lookup particular *values*, eg
SQL> create table t1
2 as select rownum num, rpad(rownum,500,'x') str, rownum id
3 from dual
4 connect by level <= 10000;
Table created.
SQL>
SQL> Create Index t1x on t1 (
2 CASE WHEN (Num < 1000 and Num > 950) THEN Str else NULL END,
3 CASE WHEN (Num < 1000 and Num > 950) THEN Id else NULL END
4 );
Index created.
SQL> select *
2 from t1
3 where CASE WHEN (Num < 1000 and Num > 950) THEN Str else NULL END = :b1
4 and CASE WHEN (Num < 1000 and Num > 950) THEN Id else NULL END = :b2;
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10000 | 4970K| 6 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 10000 | 4970K| 6 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T1X | 49 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Isn't your query just logically equivalent to a simple predicate on NUM ?
SQL> select count(*)
2 from t1
3 where CASE WHEN (Num < 1000 and Num > 950) THEN Str else NULL END = str
4 and CASE WHEN (Num < 1000 and Num > 950) THEN Id else NULL END = id;
COUNT(*)
----------
49
SQL> select count(*)
2 from t1
3 where Num < 1000 and Num > 950;
COUNT(*)
----------
49