Ned*_*ddy 5 c++ templates template-argument-deduction c++17
我想在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});
}
Run Code Online (Sandbox Code Playgroud)
但是编译这个让我"无法在调用时推断模板参数'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将有点难以维护......
想要拥有
do_thing({test})或do_thing(test)隐式构造 aBar并将其作为参数传递(如果可能)。
不幸的是,当您调用do_thing({test})or时do_thing(test),test(or {test}) 不是Bar<T>对象。所以编译器无法推导T类型,也无法构造Bar<T>对象。
有点像先有鸡还是先有蛋的问题。
我能想象的最好的方法是在 中添加Foo一个do_test()方法,如下所示
template<typename T>
auto do_thing (T const & t)
{ return do_thing(Bar{t}); }
Run Code Online (Sandbox Code Playgroud)
这样就可以调用了(无图)
std::vector<std::string> s = foo.do_thing(test);
Run Code Online (Sandbox Code Playgroud)
你得到的结果与
std::vector<std::string> s = foo.do_thing(Bar{test});
Run Code Online (Sandbox Code Playgroud)
- 编辑 -
OP问
有什么方法可以保留 {test} 大括号语法吗?也许与initializer_list或其他什么?
是的...与std::initializer_list
template<typename T>
auto do_thing (std::initializer_list<T> const & l)
{ return do_thing(Bar{*(l.begin())}); }
Run Code Online (Sandbox Code Playgroud)
但是,这样,你也接受了
std::vector<std::string> s = foo.do_thing(Bar{test1, test2, test3});
Run Code Online (Sandbox Code Playgroud)
仅使用test1
也许更好一点...另一种方法是通过 C 风格的数组
template <typename T>
auto do_thing (T const (&arr)[1])
{ return do_thing(arr[0]); }
Run Code Online (Sandbox Code Playgroud)
这样你就只接受一个元素。
| 归档时间: |
|
| 查看次数: |
167 次 |
| 最近记录: |