c++ - C++ - 具有多个参数包和 std::function 作为参数的函数
问题描述
我正在尝试在 C++ 中创建一个自动解决依赖关系的 IoC 容器。
为此,我创建了一个带有两个可变参数包的函数,声明如下:
template <class T, typename ... TDependencies, typename... TArgs>
void Register(std::function<std::shared_ptr<T> (std::shared_ptr<TDependencies> ...,
TArgs ...)> && pFactory)
显然,编译器在提供时似乎无法匹配
Register<Foo, Bar>(std::function<std::shared_ptr<Foo>(std::shared_ptr<Bar>)>(
[](std::shared_ptr<Bar> bar){return std::make_shared<Foo>(bar);}));
编译错误说
note: candidate: 'void Container::Register(std::function<std::shared_ptr<_Tp>
(std::shared_ptr<TDependencies>..., TArgs ...)>&&)
[with T = Foo; TDependencies = {Bar}; TArgs = {std::shared_ptr<Bar>}]'
显然,它匹配std::shared_ptr<Bar>
了两次。我怎样才能让编译器也与shared_ptr
TArgs 不匹配?
解决方案
TDependencies
与其尝试直接从参数类型推断,不如pFactory
编写一个类型特征来从整个参数包中获取依赖关系。与boost::mp11
:
template <class>
struct is_shared_ptr : std::false_type {};
template <class T>
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
namespace mp11 = ::boost::mp11;
template <class... Ts>
using register_traits = mp11::mp_partition<mp11::mp_list<Ts...>, is_shared_ptr>;
template <class T, class F, class... TDependencies, class... TArgs>
void RegisterImpl(F && pFactory,
mp11::mp_list<
mp11::mp_list<std::shared_ptr<TDependencies>...>,
mp11::mp_list<TArgs...>>);
template <class T, class... Ts>
void Register(std::function<std::shared_ptr<T> (Ts...)> && pFactory)
{
return RegisterImpl<T>(
std::forward<std::function<std::shared_ptr<T> (Ts...)>>(pFactory),
register_traits<Ts...>{});
}
并称之为:
Register(std::function{[] (std::shared_ptr<Bar> bar) {
return std::make_shared<Foo>(bar);
}});
如果boost::mp11
不是一个选项,您可以通过以下方式实现您自己的partition
模板元功能:
template <class...>
struct list {};
namespace detail {
template <class L, template <class...> class P, class T, class F, class = void>
struct partition;
template <class Next, class... Ls,
template <class...> class P, class T, class... Fs>
struct partition<list<Next, Ls...>, P, T, list<Fs...>,
std::enable_if_t<!P<Next>::value>> :
partition<list<Ls...>, P, T, list<Fs..., Next>> {};
template <class Next, class... Ls,
template <class...> class P, class... Ts, class F>
struct partition<list<Next, Ls...>, P, list<Ts...>, F,
std::enable_if_t<P<Next>::value>> :
partition<list<Ls...>, P, list<Ts..., Next>, F> {};
template <template <class...> class P, class T, class F>
struct partition<list<>, P, T, F> { using type = list<T, F>; };
} // namespace detail
template <class L, template <class...> class P>
using partition = typename detail::partition<L, P, list<>, list<>>::type;
template <class... Ts>
using register_traits = partition<list<Ts...>, is_shared_ptr>;
template <class T, class F, class... TDependencies, class... TArgs>
void RegisterImpl(F && pFactory,
list<list<std::shared_ptr<TDependencies>...>, list<TArgs...>>);
其余代码将保持不变。
推荐阅读
- c# - 获取目录路径
- android-studio - 如何在 setState() 之后使用动画文本更新小部件?
- java - 未能执行目标 org.apache.maven.plugins:maven-resources-plugin:2.6:resources
- php - isset($_REQUEST['button name']) 可以与声明的 id=$_POST['id'] 一起使用,还是我们需要使用相同的 $_REQUEST?
- android - android ndk 中有类似 AAsset_closeFileDescriptor 的东西吗?
- electron - Electronjs ipcMain 不会使用 ipcRenderer 将消息发送到另一个窗口
- firebase - 是否可以将静态 IP 分配给托管在 Firebase 上的网站?
- partitioning - MongoDB Realm 中的多个分区
- flutter - 日历轮播在颤动中给出范围错误
- mysql - MySQL - 子查询内的 FULL JOIN