Мой коллега предоставил мне «небольшую викторину», которую он заставил своих учеников решить один раз.Кажется, что мой слабый разум просто не в состоянии постичь всю красоту современных возможностей C ++.
Subj:
Реализация функции join
, принятие произвольных функторови возвращение другого функтора, который ведет себя как любой из них.Пример:
{
auto result = std::visit(custom::join(
[](std::string const& s) { return "it's a string"; },
[](std::pair<int, int> const& p) { return "it's a pair"; }
), var);
assert(result == "it's a string");
var = std::make_pair(10, 20);
auto lvalue_lambda = [](std::string const& s) { return "it's a string"; };
result = std::visit(custom::join(
lvalue_lambda,
[](std::pair<int, int> const& p) { return "it's a pair"; }
), var);
assert(result == "it's a pair");
}
Хорошо, после недолгих раздумий я понял, что std::variant
означает «один из перечисленных», поскольку это «типобезопасный союз», поэтому японадобится кортежПопробовал что-то вроде этого:
namespace custom
{
template<typename ...Functors>
class ResultFunctor
{
public:
ResultFunctor(Functors&&... funcs)
: m_funcs(std::make_tuple(std::move(funcs)...))
{}
template<typename ...Params>
auto operator()(Params... params) // that's where I got stuck
{
// return std::get<void(Params...)>(m_funcs)(params...); // No, the return type spoils this idea
return std::get<0>(m_funcs)(params...); // Now I need to choose the correct functor
}
private:
std::tuple<Functors...> m_funcs;
};
template<typename ...Functors>
ResultFunctor<Functors...> join(Functors&&... funcs)
{
return ResultFunctor(std::move(funcs)...);
}
}
Если бы это было только для функторов с void
типом возврата, я бы легко получил желаемый элемент кортежа.Но, похоже, нет способа определить это, тип возвращаемого значения не может быть выведен из заданных параметров (очевидно).
Другая идея состояла в том, чтобы использовать какой-то трюк SFINAE, чтобы выбрать правильную operator()()
версию, но так или иначе мне придется «пробежаться» по всем элементам кортежа (что неприятно, но все же может бытьgoogled), а затем проверьте, подходит ли этот элемент, на основе заданных параметров пакета.
Ну, вот где я сделал паузу, чтобы тщательно обдумать это.Если у кого-нибудь (кто лучше разбирается во всем этом разнообразном) есть какие-либо идеи, я был бы очень благодарен.