Reputation: 607
Consider the following code:
struct Color // This struct can't be modified
{
double grey;
double rgb[3];
};
int main()
{
double myRGB[3] = {2, 6, 9};
Color c = {10, myRGB}; // This line doesn't work
return 0;
}
How can I initialize a Color
object in one line?
In my real case scenario, Color
struct can't be change (for example, to use std::array
instead of a C-style array).
Upvotes: 14
Views: 2627
Reputation: 11250
As complement to others answers, the error is because in c++ arrays are not copyable and trying to initialize an array from an lvalue
has the semantic of invoking the copy-constructor
, the same as:
double r1[3] = {0., 0., 0.};
double r2[3] {r1} // doesn't compile
Your options are:
list-initialization
as @NathanOliver did list-initialization
as in the @SergeyA answer.Upvotes: 4
Reputation:
Call me a cheat, but...
struct Color final
{
double grey;
double rgb[3];
};
// the cheet
#define make_color( x, a, b ) Color x { a, b[0], b[1], b[2] }
int main()
{
double myRGB[3]{ 2, 6, 9 };
make_color( c, 10, myRGB ) ; // single line construction
printf("\nColor grey: %f\t rgb:[ %f, %f, %f ]", c.grey, c.rgb[0], c.rgb[1], c.rgb[2] ) ;
}
But, since that is pretty atrocious C++, I have taken a liberty of producing something slightly better...
struct Color final
{
double grey;
double rgb[3];
};
auto make_color ( double a, const double(&b)[3] ) { return Color { a, b[0], b[1], b[2] }; };
auto make_color ( double a, double b, double c, double d ) { return Color { a, b, c, d }; };
auto print_color ( Color c ) { printf("\nColor grey: %f\t rgb:[ %f, %f, %f ]", c.grey, c.rgb[0], c.rgb[1], c.rgb[2] ) ; }
//
int main()
{
double myRGB[3]{ 2, 6, 9 };
auto c = make_color( 10, myRGB ) ;
print_color(c);
auto z = make_color( 10, 0xFF, 0xA0, 0xB0 ) ;
print_color(z);
}
All in a good old SO tradition: do not question the question :)
(the mandatory Wandbox is here)
ps: I like your approach Oliver, although you do not need double braces in those init lists, of course.
Upvotes: 1
Reputation: 62553
Supposing that there is a need to use an intermediate array, here is how one can do it:
#include <utility>
#include <cstddef>
struct Color //this struct can't be modified
{
double grey;
double rgb[3];
};
template<size_t N, size_t... IX>
auto make_c_impl(double grey, double (&rgb)[N], std::index_sequence<IX...>) {
static_assert(sizeof(rgb) == sizeof(Color::rgb), "Arrays sizes must match!");
return Color{grey, {rgb[IX]...}};
}
template<size_t N>
auto make_c(double grey, double (&rgb)[N]) {
return make_c_impl(grey, rgb, std::make_index_sequence<N>{});
}
double myRGB[3] = {2, 6, 9};
Color c = make_c(10, myRGB); //this line now works
Note, that this code will not actually produce any unnecessary copying with any level of optimization.
Upvotes: 5
Reputation: 180415
Since Color
is an aggregate you can use aggregate initialization and put the array initializer directly in the braces like
Color c = {10, {2, 6, 9}};
If you have to initialize c
with an array, since it is small, you can just unroll it like
Color c = {10, {myRGB[0], myRGB[1], myRGB[2]}};
Upvotes: 18