Request Short Link
C++ 98
C++ 11
C++ 14
C++ 17
C++ 20
C++ 23
C++ 2c
for-loops as while-loops
array subscription
Show all implicit casts
Show all template parameters of a CallExpr
Use libc++
Transform std::initializer_list
Show noexcept internals
Show padding information
Show coroutine transformation
Show C++ to C transformation
Show object lifetime
Default
15
18
20
22
26
More
GitHub
Patreon
Issues
About
Policies
Examples
C++ Insights @ YouTube
Settings
Version
Workshop: Safe and Efficient C++ for Embedded Environments
×
Made by
Andreas Fertig
Powered by
Flask
and
CodeMirror
Source:
#include <memory> #include <tuple> template<typename T, typename Tuple, std::size_t Begin, std::size_t End> bool constexpr es_construible() { return []<std::size_t... I>(std::index_sequence<I...>) -> bool { return std::is_constructible_v<T, std::tuple_element_t<Begin + I, Tuple>...>; }(std::make_index_sequence<End - Begin>{}); } // El primer argumento del template es la clase que estamos construyendo // El segundo es un tupla con los tipos que hemos recibido // El tercer argumento es el Ãndice que nos indica cuántos argumentos hemos comprobado ya // lo usaremos para saber cuándo hemos llegado al final de la tupla // sin encontrar una secuencia de argumentos que nos permitan construir T template <typename T, typename Q, typename Tuple, std::size_t N = 0> struct constructor_arg_counter { // Comprobamos si tomando los N primeros argumentos podemos construir T static constexpr bool es_construibleT = es_construible<T, Tuple, 0, N>(); // Comprobamos si tomando el resto de argumentos podemos construir Q static constexpr bool es_construibleQ = es_construible<Q, Tuple, N, std::tuple_size_v<Tuple>>(); // Inicializamos la "variable de retorno" // Si hemos conseguido inicializar T, ya sabemos que necesitamos los N primeros elementos de la tupla // Si ningún constructor de T puede ser llamado con los N primeros elementos de la tupla, // aumento un elemento más y continúo la recursión. static constexpr std::size_t value = (es_construibleT && es_construibleQ) ? N : constructor_arg_counter<T, Q, Tuple, N + 1>::value; }; template <typename Tuple, std::size_t N> concept ExcedeTupla = (N > std::tuple_size_v<Tuple>); // Especialización para detener la recursión cuando N supera el tamaño de la tupla template <typename T, typename Q, typename Tuple, std::size_t N> requires ExcedeTupla<Tuple, N> struct constructor_arg_counter<T, Q, Tuple, N> { static constexpr std::size_t value = std::tuple_size_v<Tuple> + 1; }; template <std::size_t Begin, std::size_t End, typename Tuple> auto constexpr subtuple(const Tuple& tuple) { return [&tuple]<std::size_t... I>(std::index_sequence<I...>) { return std::forward_as_tuple( std::forward<std::tuple_element_t<Begin + I, Tuple>>(std::get<Begin + I>(tuple))... ); }(std::make_index_sequence<End - Begin>{}); } template <typename T, typename ArgsTuple> T* newT(ArgsTuple&& args) { return std::apply( [](auto&&... params) -> T* { return new T(std::forward<decltype(params)>(params)...); }, std::move(args)); } template <typename Object, typename Data> struct S { public: // Factoria template <typename... Args> static S create(Args&&... args) { // Convertimos los argumentos a una tupla para poder manejarlos con facilidad, // En particular queremos acceder a ellos por Ãndice auto args_tuple = std::forward_as_tuple(std::forward<Args>(args)...); // Contamos cuántos elementos de la tupla necesitamos para el primer constructor constexpr std::size_t n_args_Object = constructor_arg_counter<Object, Data, decltype(args_tuple)>::value; // Si no hemos conseguido encontrar cómo dividir la tupla, // este valor será demasiado grande y la compilación fallará static_assert(n_args_Object <= sizeof...(Args)); // Definimos la primera tupla auto&& args_Object = subtuple<0, n_args_Object>(args_tuple); // Definimos la segunda tupla auto&& args_Data = subtuple<n_args_Object, sizeof...(Args)>(args_tuple); // Pasamos las tuplas a sus respectivos constructores y devolvemos la instancia de S return S(newT<Object>(args_Object), newT<Data>(args_Data)); } private: using object_ptr = std::unique_ptr<Object>; using data_ptr = std::unique_ptr<Data>; object_ptr m_object{}; data_ptr m_data{}; // Constructor privado S(Object *o, Data *d) : m_object{o}, m_data{d} {}; }; struct O { O(char, short, int&) {} }; struct D { D(int&&) {} }; int main() { int p = 2; const auto &s = S<O, D>::create('\0', short{1}, p, 4); return 0; }
Insight:
Console: