我有一个带有模板构造函数的类,如下所示:
class Foo {
private:
std::unordered_map<std::type_index, std::vector<std::function<void(BaseT*)>>> funcs;
public:
template<class T> Foo(const std::function<void(T* arg)>& func) {
auto funcToStore = [func](BaseT* a) { func(static_cast<T*>(a)); };
this->funcs[std::type_index(typeid(T))].push_back(funcToStore);
}
}
这个类的构造函数接受一个函数参数,参数类型为 T
派生自一些基本类型 BaseT
并使用 std::type_info
将此函数存储在 vector 映射中的 T
为 key 。
因为这是一个模板构造函数而不是一个普通的函数,显式指定模板参数是行不通的,因为这是不允许的语法:
Foo* foo = new Foo<MyT>([](MyT* arg) { ... });
省略显式 <MyT>
也不会起作用,因为无法从 lambda 参数类型推导出模板参数。
所以一个解决方案是将 lambda 包装在 std::function
中对象:
Foo* foo = new Foo(std::function<void(MyT*)>([](MyT* arg) { ... }));
但这显然不是一个很好的可读语法。
到目前为止我想到的最好的方法是为 std::function
使用一个别名 :
template<class T> using Func = std::function<void(T*)>;
Foo* foo = new Foo(Func<MyT>([](MyT* arg) { ... }));
这更短,并且在使用 auto
时lambda 参数中的关键字我必须指定实际类型 MyT
只有一次,所以这最终似乎是一个不错的解决方案。
但是还有其他更短的解决方案吗?这样就不需要包装 lambda 了?喜欢:
Foo* foo = new Foo([](MyT* arg) { ... });
最佳答案
使用普通模板参数代替 std::function
:
class Foo {
std::unordered_map<size_t, std::vector<BaseT*>> funcs;
public:
template<class T> Foo(const T& func) {
// ...
}
};
现在推导将正确进行,您的代码将不会受到 std::function
的开销的影响。
如果想获取lambda第一个参数的类型怎么办?
你必须做这样的事情:
template<typename T>
struct function_traits : function_traits<&T::operator()> {};
template<typename R, typename C, typename... Args>
struct function_traits<R(C::*)(Args...) const> {
using arguments = std::tuple<Args...>;
using result = R;
};
当然,如果你想支持所有可能的函数类型,你需要32 specialisations
现在,如果需要,您可以提取参数类型甚至返回类型:
template<class T> Foo(const T& func) {
using Arg = std::tuple_element_t<0, typename function_traits<T>::arguments>;
auto funcToStore = [func](BaseT* a) { func(static_cast<Arg>(a)); };
funcs[typeid(Arg).hash_code()].push_back(funcToStore);
}
此外,由于您在构造函数中收到一个 const T&
,您可能希望将您的函数限制为只能通过可以编译的函数调用:
template<typename T>
using is_valid_foo_function = std::is_convertible<
BaseT*, // form
std::tuple_element_t<0, typename function_traits<T>::arguments> // to
>;
然后像这样使用约束:
template<class T, std::enable_if_t<is_valid_foo_function<T>::value>* = nullptr>
Foo(const T& func) {
// ...
}
关于c++ - 以 std::function 作为参数的构造函数模板参数推导,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45611094/