Вместо:
template<class... Args>
void accept_variadic(std::unique_ptr<Runnable<Args...>> o, Args&&... args)
{
o->f(forward<Args>(args)...);
}
Вы можете использовать TMP, чтобы получить то, что вы хотите:
template<class T, class... Args>
std::enable_if_t<std::is_convertible_v<std::unique_ptr<T>,
std::unique_ptr<Runnable<Args...>>>>
accept_variadic(std::unique_ptr<T> o, Args&&... args)
{
o->f(forward<Args>(args)...);
}
(полный код здесь )
Это не на 100% эквивалентно, поскольку предлагаемое решение принимает std::unique_ptr
типа Derived, в то время как исходный код будет принимать только базовый тип.
Исходный код не работает, поскольку шаблоны соответствуют типам, которые требуют преобразования.В вашем коде два типа std::unique_ptr
не являются базовыми / производными друг от друга, поэтому шаблоны не будут совпадать.
В предлагаемом решении функция принимает исходный std::unique_ptr
при условии, что его можно преобразовать в базовый тип внутри функции.std::enable_if_t
гарантирует, что другие типы не совпадают, только те, которые могут быть преобразованы в базу.
Редактировать
В некоторых вариантах вопроса первоначальное решение может бытьпроблематичным.Это может произойти в вариантах вопросов, в которых вызов f()
в базовом классе обрабатывается иначе, чем вызов f()
в производном классе.Есть несколько возможностей, когда это может произойти (но не в оригинальном вопросе).Чтобы преодолеть этот риск, accept_variadic()
следует изменить на:
template<class T, class... Args>
std::enable_if_t<std::is_convertible_v<T&, Runnable<Args...>&>>
accept_variadic(std::unique_ptr<T> o, Args&&... args)
{
// could also be solved with
// std::unique_ptr<Runnable<Args...>> base = std::move(o);
Runnable<Args...> & runnable = *o;
runnable.f(forward<Args>(args)...);
}