Reputation: 10941
I want to initialize an object with an initializer list. The problem is, an initializer list is able to contain unpredictable number of elements, but I need to initialize only for variables. The user may send any number of list elements, and I need only four of them.
I wrote the following code, but it looks like very long and inefficient to me. Is there any better way of doing this?
Pixel::Pixel(std::initializer_list<uint8_t> Channels)
{
switch (Channels.size())
{
case 0:
R = 0;
G = 0;
B = 0;
A = 0;
break;
case 1:
R = *(Channels.begin() + 0);
G = 0;
B = 0;
A = 0;
break;
case 2:
R = *(Channels.begin() + 0);
G = *(Channels.begin() + 1);
B = 0;
A = 0;
break;
case 3:
R = *(Channels.begin() + 0);
G = *(Channels.begin() + 1);
B = *(Channels.begin() + 2);
A = 0;
break;
default:
R = *(Channels.begin() + 0);
G = *(Channels.begin() + 1);
B = *(Channels.begin() + 2);
A = *(Channels.begin() + 3);
}
}
(Note: I know this can be done with passing the R, G, B, A values with four separate arguments. But my main purpose is to learn how to do this with the initializer list feature.)
Upvotes: 1
Views: 409
Reputation: 69942
the best I could come up with when using std::initialiser_list
struct Pixel
{
Pixel(std::initializer_list<uint8_t> rgba)
: _rgba { rgba }
{
switch(_rgba.size()) {
case 0: _rgba.push_back(0);
case 1: _rgba.push_back(0);
case 2: _rgba.push_back(0);
case 3: _rgba.push_back(0);
case 4: break;
default:
throw std::invalid_argument { "" };
}
}
std::vector<uint8_t> _rgba;
};
... but ...
Probably the correct way to solve this problem is this:
struct Pixel
{
Pixel(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0, uint8_t a = 0)
: R(r)
, G(g)
, B(b)
, A(a)
{}
uint8_t R,G,B,A;
};
because
examples:
int main()
{
Pixel p1 { 10, 20, 5, 255 };
Pixel p2 { 10, 20, 5 };
Pixel p3 { 10, 20 };
Pixel p4 { 10 };
Pixel p5 { };
Pixel pv1 ( 10, 20, 5, 255 );
Pixel pv2 ( 10, 20, 5 );
Pixel pv3 ( 10, 20 );
Pixel pv4 ( 10 );
Pixel pv5;
return 0;
}
Upvotes: 4
Reputation: 218323
You may rewrite you switch as follow:
Pixel::Pixel(std::initializer_list<uint8_t> Channels) : R(0), G(0), B(0), A(0)
{
switch (Channels.size())
{
default: // Too many args
case 4: A = *(Channels.begin() + 3); // No break: Follow next line
case 3: B = *(Channels.begin() + 2); // No break: Follow next line
case 2: G = *(Channels.begin() + 1); // No break: Follow next line
case 1: R = *(Channels.begin() + 0);
case 0: break;
}
}
Upvotes: 4