A continuación hay dos plantillas en su mayoría idénticas PgmArray y PgmArrayF. El primero funciona para parámetros de plantilla lvalue-ref, el segundo funciona para parámetros integrales. Me gusta combinar estos dos en uno:

#include <stdint.h>
#include <type_traits>
#include <array>
#include <iostream>

template<typename T, const T&... Ts>
struct PgmArray final {
    static constexpr uint8_t size = sizeof... (Ts);
    static constexpr T data[] {Ts...};
};

template<typename T, T... Ts>
struct PgmArrayF final {
    static constexpr uint8_t size = sizeof... (Ts);
    static constexpr T data[] {Ts...};
};

struct A{
    uint8_t m = 0;
};

constexpr A a1{1};
constexpr A a2{2};

constexpr auto x1 = PgmArray<A, a1, a2>{}; // ok
constexpr auto x2 = PgmArrayF<int, 1, 2>{}; // ok

//constexpr auto x3 = PgmArrayF<A, a1, a2>{}; // nok
//constexpr auto x4 = PgmArray<int, 1, 2>{}; // nok

int main() {
}
2
wimalopaan 15 jun. 2017 a las 14:34

3 respuestas

La mejor respuesta

Vamos a revertir lo que hizo @bolov y poner la manipulación en el tipo de paquete de parámetros:

// separate alias template not strictly necessary, but easier for readability
template<class T>
using maybe_cref = std::conditional_t<std::is_integral_v<T>, T, const T&>;

template <typename T, maybe_cref<T>... Ts>
struct PgmArray final {
    static constexpr uint8_t size = sizeof... (Ts);
    static constexpr T data[] {Ts...};
};
2
T.C. 15 jun. 2017 a las 19:14

No es menos código, sino más fácil de mantener si cambia PgmArray con frecuencia.

template<typename T, T... Ts>
struct PgmArray final {
    static constexpr uint8_t size = sizeof... (Ts);
    static constexpr std::decay_t<T> data[] {Ts...};
};

template<typename T>
struct MakePgmArray {
    using TemplateArgument = typename std::conditional_t<
            std::is_integral_v<T>, T, const T&>;
    template<TemplateArgument... Ts>
    using type = PgmArray<TemplateArgument, Ts...>;
};

...

constexpr auto x1 = MakePgmArray<A>::type<a1, a2>{}; // ok
constexpr auto x2 = MakePgmArray<int>::type<1, 2>{}; // ok
5
petersohn 15 jun. 2017 a las 11:56

Inspirado por la respuesta de petersohn

También puedes hacer esto:

template <typename U, U... Ts>
struct PgmArray final {
    using T = std::remove_const_t<std::remove_reference_t<U>>;

    static constexpr uint8_t size = sizeof... (Ts);
    static constexpr T data[] {Ts...};
};

constexpr auto x3 = PgmArray<const A&, a1, a2>{}; // ok
constexpr auto x4 = PgmArray<int, 1, 2>{}; // ok
4
bolov 15 jun. 2017 a las 12:03