es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Plantillas variádicas de C++

Estoy usando una definición de vector:

     vector<lmlink_out> os{
lmlink_out(typeid(string &)),
lmlink_out(),
lmlink_out(typeid(int),typeid(char))
};

usando el siguiente código funciona (definido dentro de la clase):

class lmlink_out {
vector<const type_info*> parameters;

public:
template<typename… T, std::size_t N = sizeof…(T)>
lmlink_out(const T&… args) : parameters({&args…}) {}

usar esto otro da lugar a un error de compilación (definido fuera de la clase):

class lmlink_out {
vector<const type_info*> parameters;

public:
template<typename… T, std::size_t N = sizeof…(T)>
lmlink_out(const T&… args);
};

template<typename… T, std::size_t N = sizeof…(T)>
lmlink_out::lmlink_out(const T&… args)
parameters({(&args…})
{
}

el compilador (versión gcc 10.2.1 20210110 (Debian 10.2.1-6)) devuelve:

error: no se encontró una función coincidente para llamar a ‘std::vector<const
std::typeinfo*>::vector()’ 374 |
parameters({(&args…}) nota: el candidato es: ‘std::vector<Tp,
Alloc>::vector(std::initializerlist<Tp>, const allocatortype&) [con Tp = const std::typeinfo; _Alloc = std::allocator>; std::vector<Tp, _Alloc>::allocatortype =
std::allocatorinfo*>]’ 625 |
vector(initializer
list<valuetype> _l,

| ^~~~~~ /usr/include/c++/10/bits/stlvector.h:625:43: nota: no hay una conversión conocida para el argumento 1 de ‘’ a ‘std::initializerlist

Creo que los dos códigos son semánticamente equivalentes, ¿por qué el segundo da un error?

Necesito agregar otro constructor:

template<typename… T, std::size_t N = sizeof…(T)>
lmlink_out(const string &name, const T&… args) : name(name), parameters({&args…}) {}

pero da lugar al mismo error mencionado anteriormente.

Tags:  ,

Answer

  1. Avatar for davy.ai

    La razón por la cual el segundo código da lugar a un error de compilación es que la sintaxis para utilizar una expansión de paquete de parámetros dentro de una lista de inicializadores delimitada por llaves no está permitida fuera de una clase o función de plantilla. El compilador no puede deducir los tipos de la expansión del paquete de parámetros y, por lo tanto, no puede construir el vector.

    Para solucionar el error, puedes mantener la definición del constructor dentro de la clase o utilizar una función separada para construir el vector. Por ejemplo:

    class lmlink_out {
        vector<const type_info*=""> parameters;
        ...
    public:
        template<typename... t="">
        lmlink_out(const string& name, const T&... args)
            : name(name), parameters(make_vector(args...))
        {}
    private:
        template<typename... t="">
        static vector<const type_info*=""> make_vector(const T&... args) {
            return {&typeid(args)...};
        }
    };
    

    Aquí, definimos una función privada make_vector que construye el vector utilizando una expansión de paquete de parámetros dentro de una lista de inicializadores delimitada por llaves. El constructor lmlink_out llama a esta función para inicializar el miembro parameters.

    De esta manera, el código se compilará sin errores y podrás agregar el nuevo constructor con un parámetro de tipo string y una expansión de paquete de parámetros para inicializar el miembro parameters de la misma manera que el constructor original.</typename…></typename…>

Comments are closed.