无法检索元组中的构造函数参数。
我正在尝试将给定类的构造函数参数类型提取为
std::tuple
。例如,如果我有一堂这样的课:
struct MyClass {
MyClass(int, double, std::string) {}
};
我想获取像
std::tuple<int, double, std::string>
这样的类型对应构造函数的参数。
我知道在 Boost.DI 中,这似乎是可以实现的,因为它们设法自动解决构造函数依赖关系。但是,我找不到关于他们如何提取构造函数的参数类型的明确解释。
对于常规功能,我知道如何将
std::tuple
与模板一起使用,如下所示:
template <typename Func>
struct function_traits;
// Specialization for functions
template <typename Ret, typename... Args>
struct function_traits<Ret(Args...)> {
using args_tuple = std::tuple<Args...>;
};
但是,我不确定如何为构造函数采用这种方法。
限制:
有人可以指导我如何实现这一目标吗?也许是一个最小的例子或解释 Boost.DI 如何做到这一点?
如果有多个构造函数,boost di 表示它会选择最长的构造函数。它也是怎么做到的?
boost di 的工作原理示例(来自官方文档)。 参考:增强示例
// $CXX -std=c++14 basic_create_objects_tree.cpp
#include <boost/di.hpp>
namespace di = boost::di;
struct renderer {
int device;
};
class view {
public:
view(std::string /*title*/, const renderer&) {}
};
class model {};
class controller {
public:
controller(model&, view&) {}
};
class user {};
class app {
public:
app(controller&, user&) {}
};
int main() {
/**
* renderer renderer_;
* view view_{"", renderer_};
* model model_;
* controller controller_{model_, view_};
* user user_;
* app app_{controller_, user_};
*/
auto injector = di::make_injector();
injector.create<app>();
}
我想我有使用这个文件的线索,但我仍然无法完全理解该系统以及如何实现它。 boost/di/type_traits/ctor_traits.hpp
首先,计算它们有多少个参数(使用 Ted Lyngmo 的代码)(带有硬编码限制):
template<class T, std::size_t I>
struct Any {
template<class U>
operator U() const;
};
template <class T, size_t N>
struct is_valid_amount {
static std::false_type test(...);
template <std::size_t... Is>
static auto test(std::index_sequence<Is...>)
-> decltype(T(Any<T, Is>{}...), std::true_type{});
static constexpr bool value =
decltype(test(std::make_index_sequence<N>{}))::value;
};
template <class T, size_t N>
inline constexpr bool is_valid_amount_v = is_valid_amount<T, N>::value;
template<class T, std::size_t N>
struct ctor_def : std::integral_constant<std::size_t, N> {
};
template <class T, std::size_t N = 16> // increase max amount of args if you wish
struct ctor_arg_count
: std::conditional_t<is_valid_amount_v<T, N>,
ctor_def<T, N>,
ctor_arg_count<T, N - 1>> {};
template<class T>
inline constexpr std::size_t ctor_arg_count_v = ctor_arg_count<T>::value;
然后,通过有状态元编程,您可能会这样做:
namespace details
{
template<std::size_t N> struct tag{};
template<typename T, std::size_t N>
struct loophole_t {
friend auto loophole(details::tag<N>) { return std::type_identity<T>{}; };
};
auto loophole(tag<0>);
auto loophole(tag<1>);
auto loophole(tag<2>);
auto loophole(tag<3>);
auto loophole(tag<4>);
auto loophole(tag<5>);
auto loophole(tag<6>);
auto loophole(tag<7>);
auto loophole(tag<8>); // Add extra
template <std::size_t N>
struct detector {
template <class T, std::size_t = sizeof(details::loophole_t<T, N>)>
operator T();
};
template<typename T, typename Seq> struct ins;
template<typename T, std::size_t... Is>
struct ins<T, std::index_sequence<Is...>>
{
template <std::size_t = sizeof(T{detector<Is>{}...})>
constexpr int operator()() const { return 0; }
};
template <std::size_t, std::size_t... Is, typename T = std::tuple<typename decltype(loophole(details::tag<Is>{}))::type...>>
T get_type_impl(std::index_sequence<Is...>);
template <typename T, std::size_t N = details::ctor_arg_count_v<T>>
auto get_type()
{
return details::get_type_impl<details::ins<T, std::make_index_sequence<N>>{}()>(std::make_index_sequence<N>());
}
}
template <typename T>
using constructor_type_as_tuple_t = decltype(details::get_type<T>());