Параметр шаблона не может быть выведен на неявно построенный аргумент - PullRequest
0 голосов
/ 29 декабря 2018

Я хотел бы иметь следующий код на c ++ 17:

#include <iostream>
#include <string>
#include <type_traits>
#include <functional>

class Foo;

template<class T>
class Bar {
public:

    std::function<T(Foo&)> m_fn;

    template<class Fn>
    Bar(Fn fn) : m_fn(fn) {};

    T thing(Foo &foo) const {
        return m_fn(foo);
    }
};


template<class Fn>
Bar(Fn) -> Bar<decltype(std::invoke(std::declval<Fn>(),
                                    std::declval<Foo&>()))>;

class Foo {
public:
    Foo() {};

    template<class T>
    std::vector<T> do_thing(const Bar<T> &b) {
        std::vector<T> r;

        r.push_back(b.thing(*this));

        return r;
    }
};


std::string test(Foo &) {
    return "hello";
}

int main() {
    Foo foo = Foo();

    // works
    std::vector<std::string> s = foo.do_thing(Bar{test});

    // cant deduce T parameter to do_thing
    std::vector<std::string> s = foo.do_thing({test});
}

Но компиляция этого дает мне "не удалось вывести параметр шаблона 'T'" при вызове do_thing.Наличие do_thing(Bar{test}) исправляет это и работает нормально, но приравнивается к некрасивому коду в эквиваленте реального кода.Я хотел бы, чтобы do_thing({test}) или do_thing(test) неявно создавали Bar и передавали его в качестве аргумента, если это возможно.

Я также не хочу пересылать объявление переменной для передачи в do_thingлибо

Есть ли какой-нибудь способ сделать вывод аргумента шаблона T, чтобы вызов do_thing мог оставаться чистым?

Редактировать:

Извините заПозднее редактирование, но аргументы конструктора Bar слишком упрощены в приведенном мной примере.В действительности есть дополнительный параметр std::optional<std::string> desc = std::nullopt, который может измениться в будущем (хотя вряд ли).Поэтому построение Bar внутри do_thing будет немного сложным для поддержки ...

Ответы [ 2 ]

0 голосов
/ 30 декабря 2018

Это происходит потому, что {} не является выражением и может использоваться только ограниченным образом при выводе аргумента, для успеха параметр должен иметь определенные формы.

Допустимые типы параметров, которые могут бытьИспользуемый для вывода параметров шаблона, когда задействован {}, лучше развернуть в [temp.deduct.call] / 1 , два из примеров, извлеченных из процитированной части стандарта::

template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int

template<class T, int N> void h(T const(&)[N]);
h({1,2,3}); // T deduced to int

В вашем примере руководство по выводам не используется для вывода T для {test} для того же, что и выше.

foo.do_thing(Bar{test});

- это ваш прямой выбор без использованиядополнительные функции.

0 голосов
/ 30 декабря 2018

хотел бы, чтобы do_thing({test}) или do_thing(test) неявно создавали Bar и передавали это в качестве аргумента, если это возможно.

К сожалению, когда вы вызываете do_thing({test}) илиdo_thing(test), test (или {test}) не является Bar<T> объектом.Таким образом, компилятор не может определить тип T и не может создать объект Bar<T>.

Этакая проблема с яйцом и яйцом.

Лучшее, что я могу себе представитьсостоит в том, чтобы добавить в Foo метод do_test() следующим образом

template<typename T>
auto do_thing (T const & t)
 { return do_thing(Bar{t}); } 

Таким образом, вы можете вызывать (без графиков)

std::vector<std::string> s = foo.do_thing(test);

Вы получите тот же результат, что и

std::vector<std::string> s = foo.do_thing(Bar{test});

- РЕДАКТИРОВАТЬ -

ОП спрашивает

Есть ли способ сохранить синтаксис {test} фигурной скобки?может быть с initializer_list или чем-то?

Да ... с std::initializer_list

template<typename T>
auto do_thing (std::initializer_list<T> const & l)
{ return do_thing(Bar{*(l.begin())}); }

но, таким образом, вы также принимаете

std::vector<std::string> s = foo.do_thing(Bar{test1, test2, test3});

, используятолько test1

Может быть, немного лучше ... другой путь может быть через массив в стиле C

template <typename T>
auto do_thing (T const (&arr)[1])
 { return do_thing(arr[0]); }

Таким образом, вы принимаете только элемент.

...