Sobre la base de esta respuesta:

https://stackoverflow.com/a/3319851/13250135

Me gustaría estructurar los parámetros de mi plantilla en esquemas, porque las mismas clases se usan en diferentes contextos en la misma aplicación.

// adapted from https://stackoverflow.com/a/3319851
template<typename _string, typename _real>
struct scheme{
    public:
    using string = _string;
    using real = _real;
};

using scheme1 = scheme<std::string_view, double>;
using scheme2 = scheme<std::string, float>;

template<class scheme>
class Test {
    scheme::string text;
    scheme::real value;
    std::array<int, 10> array{};
};

Test<scheme1> test1{};
Test<scheme2> test2{};

Hasta ahora tan bueno. Pero ahora necesito un tipo que sea paramétrico en sí mismo. Por ejemplo, me gustaría parametrizar igualmente el std::array<T> con alternativas potenciales.

EDITAR: para agregar más información.

Me gustaría lograr algo así:

template<typename _string, typename _real, typename _collection>
struct scheme{
    public:
    using string = _string;
    using real = _real;
    using collection = _collection;
};

using scheme1 = scheme<std::string_view, double, std::array>;
using scheme2 = scheme<std::string, float, myNamespace::myArray>;

template<class scheme>
class Test {
    scheme::string text;
    scheme::real value;
    scheme::collection<int, 10> array{};
};

Pero, por supuesto, esto no funciona, ya que std::array sin parámetros no es un nombre de tipo válido. Pero necesito poder proporcionar estos parámetros finales solo donde se crea una instancia de la plantilla, p. Ej. en la clase Test.

¿Por qué querría algo así?

Algunas clases deben usarse tanto en un esquema constexpr (todos los datos constantes, obviamente), pero también en varios esquemas no constantes. Por ejemplo, podría usar std::string_view, para el esquema constexpr y std::string para el esquema no constante.

Otro ejemplo podría ser proporcionar compatibilidad con datos que se conservan en esquemas de datos binarios específicos de la versión (migración de datos de 32 bits a 64 bits, página de códigos a Unicode, etc.). Las versiones más nuevas de la aplicación deberían implementar todos los esquemas para poder leer los datos antiguos después de la actualización.

Gracias, Mark

1
markmaker 22 ene. 2021 a las 18:24

1 respuesta

La mejor respuesta

Debe convertir _collection en un parámetro de plantilla de plantilla.

template<typename _string, typename _real, template<typename, size_t> typename _collection>
struct scheme{
    public:
    using string = _string;
    using real = _real;
    // This is now a template type alias, i.e. "variable inside the scheme"
    template<typename T, size_t N>
    using collection = _collection<T, N>;
};

Tu clase Test se vería de la siguiente manera:

template<class scheme>
class Test {
    scheme::string text;
    scheme::real value;
    // As collection is no longer a type, the additional template disambiguator is needed here...
    scheme::template collection<int, 10> array{};
};

Tenga en cuenta que esta solución solo funcionará para plantillas con la misma "firma" que std::array, es decir, un parámetro de tipo seguido de un parámetro integral que no sea de tipo. std::vector, por ejemplo, no funcionará. Por esta razón, dependiendo del tipo real de myNamespace::myArray, esta solución podría no ser viable para su problema.

Editar: Me di cuenta de que agregaste la etiqueta c ++ 20 a tu pregunta. En este caso, puede omitir los tres typename s en la clase Test. Código activo aquí.

4
florestan 22 ene. 2021 a las 16:53