Estoy tratando de crear algo similar a tuple, pero me he encontrado con un problema para escribir mi constructor.Cómo crear un constructor de reenvío perfecto para una clase variable tuple
Aquí está el código:
#include <tuple>
template <typename... Ts>
struct B {
template <typename... ArgTypes>
explicit B(ArgTypes&&... args)
{
static_assert(sizeof...(Ts) == sizeof...(ArgTypes),
"Number of arguments does not match.");
}
};
struct MyType {
MyType() = delete;
MyType(int x, const char* y) {}
};
int main()
{
B <int, char> a{2, 'c'}; // works
B <int, bool, MyType, char> b{2, false, {4, "blub"}, 'c'}; // fails
std::tuple<int, bool, MyType, char> t{2, false, {4, "blub"}, 'c'}; // works
}
Ahora, esto funciona bien si pasar a tipos simples como inicializadores, pero no es así, si trato de pasar argumentos en una lista de inicialización corsé-cerrado para no trivial objeto.
GCC-4.7 emite el siguiente:
vararg_constr.cpp:21:67: error: no matching function for call to 'B<int, bool, MyType, char>::B(<brace-enclosed initializer list>)'
vararg_constr.cpp:21:67: note: candidates are:
vararg_constr.cpp:6:14: note: B<Ts>::B(ArgTypes&& ...) [with ArgTypes = {}; Ts = {int, bool, MyType, char}]
vararg_constr.cpp:6:14: note: candidate expects 0 arguments, 4 provided
Clang-3.1 lo siguiente:
vararg_constr.cpp:21:40: error: no matching constructor for initialization of
'B<int, bool, MyType, char>'
B <int, bool, MyType, char> b{2, false,{4, "blub"}, 'c'}; // fails
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
vararg_constr.cpp:6:14: note: candidate constructor not viable: requires 2
arguments, but 4 were provided
explicit B(ArgTypes&&... args)
Ok, ahora lo que me hace muy, muy curioso es que funciona para tupla! De acuerdo con el estándar (20.4.2.1) tiene un constructor, que se parece mucho al mío.
template <class... Types>
class tuple {
public:
// ...
template <class... UTypes>
explicit tuple(UTypes&&...);
// ...
};
Al construir el objeto tupla de la misma manera, ¡funciona!
Ahora me gustaría saber:
A) ¿Qué demonios? ¿Por qué std :: tuple es tan especial y por qué los compiladores no deducen la cantidad correcta de argumentos?
B) ¿Cómo puedo hacer esto?
A) ¿Cómo sabe el compilador para el constructor de tuplas que es una tupla y no MyType? B) Lo siento, debería haber elaborado un poco sobre la tupla. Tuple está parametrizado en Ts ..., pero el constructor del que estoy hablando está además parametrizado en UTypes .... –
He editado para hacer que el problema A) sea un poco más claro – ipc
Tenga en cuenta que para la parte A, poner '&&' en los parámetros de la plantilla adjunta cambia el significado para que ya no sea un reenvío perfecto, pero (salvo los argumentos de referencia para ' Ts') forman referencias rvalue, que no son deseables. Para la parte B, las referencias rvalue se "corrigen" para lvalue 'const &', por lo que generalmente funcionará, pero aún así no es un reenvío perfecto. – Potatoswatter