Чтобы смоделировать, что делает компилятор, вам нужно что-то вроде этого:
runner_t<decltype((j))> rt{};
rt(j);
Нам нужно передать тип выражения j
(что мы делаем с дополнительными скобками). Это lvalue, так что вы получаете T = int&
и T&& = int&
, которые мы можем передать j
как.
Это раньше не работало, потому что с T = int
, T&& = int&&
, который может только быть привязанным к rvalues, поэтому вам придется сделать что-то вроде rt(int{j})
(кстати, decltype((int{j})) = int
, поэтому runner_t<decltype((int{j}))>{}(int{j})
все равно будет работать)