Вывод типа аргумента шаблона из определения класса

Можно ли использовать вывод аргументов шаблона класса для класса C из определения одной из функций-членов C? ... или я должен написать свой вспомогательный класс make_c, как в C ++ 03?

Рассмотрим этот минимизированный и упрощенный сценарий, который строит цепочку произвольных функциональных объектов:

template <typename F>
struct node;

template <typename FFwd>
node(FFwd&&) -> node<std::decay_t<FFwd>>;

В классе node хранится функциональный объект, который инициализируется с помощью перенаправления. Мне нужно здесь руководство по дедукции, чтобы decay определить тип объекта функции.

template <typename F>
struct node
{
    F _f;

    template <typename FFwd>
    node(FFwd&& f) : _f{std::forward<FFwd>(f)}
    {
    }

    template <typename FThen>
    auto then(FThen&& f_then)
    {
        return node{[f_then = std::move(f_then)]
                    { 
                        return f_then(); 
                    }};
    }
};

После этого я определяю конструктор node и функцию-член продолжения .then, которая возвращает новый узел (его реализация бессмысленна для минимизации размера примера). Если я попытаюсь вызвать _10 _...

auto f = node{[]{ return 0; }}.then([]{ return 0; });

... Я получаю неожиданную ошибку компиляции:

prog.cc: In instantiation of 'node<F>::node(FFwd&&) [with FFwd = node<F>::then(FThen&&) [with FThen = main()::<lambda()>; F = main()::<lambda()>]::<lambda()>; F = main()::<lambda()>]':
prog.cc:27:22:   required from 'auto node<F>::then(FThen&&) [with FThen = main()::<lambda()>; F = main()::<lambda()>]'
prog.cc:35:56:   required from here
prog.cc:17:46: error: no matching function for call to 'main()::<lambda()>::__lambda1(<brace-enclosed initializer list>)'
     node(FFwd&& f) : _f{std::forward<FFwd>(f)}
                                              ^
prog.cc:35:20: note: candidate: 'constexpr main()::<lambda()>::<lambda>(const main()::<lambda()>&)'
     auto f = node{[]{ return 0; }}.then([]{ return 0; });
                    ^

живой пример на wandbox

Это происходит потому, что внутри тела node<F>::then node{...} создает экземпляр с типом *this - он не запускает выведение типа аргумента. Поэтому я вынужден написать:

template <typename FThen>
auto then(FThen&& f_then)
{
    auto l = [f_then = std::move(f_then)]{ return f_then(); };
    return node<std::decay_t<decltype(l)>>{std::move(l)};
}

живой пример на wandbox

... что сводит на нет всю цель руководства по дедукции.

Есть ли способ использовать здесь вывод аргументов шаблона класса без повторения кода или make_node функции?


person Vittorio Romeo    schedule 10.07.2017    source источник


Ответы (2)


Поиск имени для node обнаружил внедренное имя-класса, из которого не выполняется вывод. (Выполнение дедукции в этом случае было бы нарушением обратной совместимости.)

Если вы хотите вычитать, уточните имя, чтобы найти член пространства имен.

template <typename FThen>
auto then(FThen&& f_then)
{
    return ::node{[f_then = std::move(f_then)]
    //     ^^
                { 
                    return f_then(); 
                }};
}

Кроме того, более понятный способ написать руководство -

template <typename F>
node(F) -> node<F>;
person T.C.    schedule 10.07.2017
comment
У меня было ощущение, что я упускаю что-то простое. Ваше здоровье. Приму как можно скорее. - person Vittorio Romeo; 10.07.2017
comment
Бесполезно ли распад шрифта в руководстве по дедукции? Или для чего нужен путеводитель по уборке? - person Mário Feroldi; 12.07.2017
comment
@ MárioFeroldi Если руководство принимает аргумент путем пересылки ссылки, то вам необходимо вручную изменить тип (для варианта использования в OP); если он принимает аргумент по значению, тогда язык распадается за вас, и вам не нужно вручную его разрушать. - person T.C.; 12.07.2017

Я нашел возможное решение, но оно требует внешней реализации функции make.

Хорошие новости: он не обязательно должен быть make_node - он может работать с любым типом T, который поддерживает вывод аргументов шаблона класса.

template <template <typename...> class T, typename... Ts>
auto make(Ts&&... xs)
    noexcept(noexcept(T{std::forward<Ts>(xs)...}))
    -> decltype(T{std::forward<Ts>(xs)...})
{
    return T{std::forward<Ts>(xs)...};
}

Использование:

template <typename FThen>
auto then(FThen&& f_then)
{
    return make<node>([f_then = std::move(f_then)]
                     { 
                         return f_then(); 
                     });
}
person Vittorio Romeo    schedule 10.07.2017