Reputation: 5472
Below are two mostly identical templates PgmArray
and PgmArrayF
. The first one works for lvalue-ref template parameters, the second one work for integral parameters. I like to combine these two into one:
#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() {
}
Upvotes: 2
Views: 118
Reputation: 137405
Let's just reverse what @bolov did and put the manipulation into the parameter pack's type:
// 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...};
};
Upvotes: 2
Reputation: 75765
Inspired by petersohn's answer
You could also do this:
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
Upvotes: 4
Reputation: 11730
It's not less code, but more maintainable if you change PgmArray often.
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
Upvotes: 5