I have a class Color
which is a thin wrapper around std::array
. I would like to be able to use it in 2 ways:
Color<5> color{1,2,3,4,5}
should produce color.values = [1,2,3,4,5]
Color<5> color{3}
should produce color.values = [3,3,3,3,3]
What I currently have is:
template <size_t N>
class Color {
public:
Color() = default;
Color(std::array<float, N> values) : values{ values } {};
template <IsNumeric... T>
Color(T... v) : values{ static_cast<float>(v)... } { };
....
private:
std::array<float, N> values;
}
This works correctly for my first-case. However for the second case it only produces: color.values = [3,0,0,0,0]
. I am at a loss for how to get the second case to work. I have tried:
template <size_t N>
class Color {
public:
Color() = default;
Color(std::array<float, N> values) : values{ values } {};
template <IsNumeric... T, typename std::enable_if<(sizeof...(T) == N), bool>::type = true>
Color(T... v) : values{ static_cast<float>(v)... } { };
template <IsNumeric T>
Color(T v) : values{ std::array<float, N>{ static_cast<float>(v) } } { };
...
}
But this does not change anything.
You can do this with the help of std::index_sequence
and a helper function. Since you are already using concepts you should use a requires
clause to replace std::enable_if
.
Your code doesn't show what type the member values
is, but the question title as well as the other constructor seems to imply that it is a std::array
and that is what I use here. Anyway it should work as long as the type of values
has a variadic constructor that does the correct thing.
namespace detail{
template <std::size_t... Is, typename T>
constexpr std::array<float, sizeof...(Is)> makeValues(std::index_sequence<Is...>, T v){
return {((void)Is, v)...};
}
}
template <size_t N>
class Color {
public:
constexpr Color() = default;
//constexpr Color(std::array<float, N> values) : values{ values } {};
template <IsNumeric... T> requires (sizeof...(T) == N)
constexpr Color(T... v) : values{ static_cast<float>(v)... } { };
template <IsNumeric T>
constexpr Color(T v) : values{detail::makeValues(std::make_index_sequence<N>{}, static_cast<float>(v))} { };
std::array<float, N> values;
};
It can be verified by the following test main function:
int main(){
static_assert(Color<2>{5,4}.values == std::array<float,2>{5,4});
static_assert(Color<2>{5}.values == std::array<float,2>{5,5});
// Color<3> doesntCompile{1,2};
}