admin管理员组

文章数量:1405747

Was looking through cppreference and could not find anything similar to what I would like to use.

I would like to explicitly initialise only a single member of a struct/union. For this reason I can't use the U{value1,value2} syntax (seems to be referred to as "declaration list" syntax) for structs, though this wouldn't work for unions. I have access to a pointer-to-member and would like to know if there's a way to use it to initialise a struct in this context. For my purposes, the union is not aggregate.

union U {
  int    a;
  double b;
};

static constexpr inline auto a_ptr = &U::a;
static constexpr inline auto b_ptr = &U::b;

static constexpr inline U u1 = U{}; // fine
static constexpr inline U u2 = U{.b = 1.0 }; // fine in this example, but only works if U is aggregate, need something else
static constexpr inline U u3 = U{.*b_ptr = 1.0 }; // syntax error

This fails to compile with a syntax error. The same issue arises when I attempt the same thing with a struct.

The syntax error reads as expected primary-expression before ‘{’ token.

A solution would also need to work for

union U {
  constexpr inline ~U() {
    // assume memory leak handled external
  }

  int         a;
  double      b;
  std::string c;
};

static constexpr inline U u = U{.c = "lorem ipsum" };

when you have a c_ptr equal to &U::c.

Was looking through cppreference and could not find anything similar to what I would like to use.

I would like to explicitly initialise only a single member of a struct/union. For this reason I can't use the U{value1,value2} syntax (seems to be referred to as "declaration list" syntax) for structs, though this wouldn't work for unions. I have access to a pointer-to-member and would like to know if there's a way to use it to initialise a struct in this context. For my purposes, the union is not aggregate.

union U {
  int    a;
  double b;
};

static constexpr inline auto a_ptr = &U::a;
static constexpr inline auto b_ptr = &U::b;

static constexpr inline U u1 = U{}; // fine
static constexpr inline U u2 = U{.b = 1.0 }; // fine in this example, but only works if U is aggregate, need something else
static constexpr inline U u3 = U{.*b_ptr = 1.0 }; // syntax error

This fails to compile with a syntax error. The same issue arises when I attempt the same thing with a struct.

The syntax error reads as expected primary-expression before ‘{’ token.

A solution would also need to work for

union U {
  constexpr inline ~U() {
    // assume memory leak handled external
  }

  int         a;
  double      b;
  std::string c;
};

static constexpr inline U u = U{.c = "lorem ipsum" };

when you have a c_ptr equal to &U::c.

Share Improve this question edited Mar 8 at 2:31 notgapriel asked Mar 7 at 12:38 notgaprielnotgapriel 1111 silver badge6 bronze badges 26
  • 2 please include the compiler error message in the question – 463035818_is_not_an_ai Commented Mar 7 at 12:41
  • 2 You are probably setting yourself up to fail anyway (syntax error or not). Unions in C++ are UB traps: For example : Imagine reading from the dereferenced pointer from an inactive union member... immediate UB. I usually avoid unions (unless I can use an unnamed one or if I can tag it). In all other cases just use variant. So my question back is WHY do you think you need this? If you use the union for type punning. Sorry that's also UB in C++ (you need to use memcpy or std::bitcast for that) – Pepijn Kramer Commented Mar 7 at 12:55
  • 5 my simplistic view is: U u2 = U{.b = 1.0 }; is no actually member access as you want it to be. Its rather special syntax to intruct the compiler to initialize the member called .b with the initializer 1.0. There is no *b_ptr member, so you attempt is a syntax error. Of course I dont leave it at the simplistic view but when I read here en.cppreference/w/cpp/language/aggregate_initialization I find no hint that it would be wrong – 463035818_is_not_an_ai Commented Mar 7 at 13:16
  • 3 static constexpr inline U u3 = (b_ptr == &U::b) ? U{.b = 1.0 } : U{.a = 0}; – Eljay Commented Mar 7 at 13:31
  • 1 a_ptr and b_ptr have two different types? How do you want to use this? How do you store the pointer-to-member? – jabaa Commented Mar 7 at 14:07
 |  Show 21 more comments

1 Answer 1

Reset to default 1

I will focus on:

I have access to a pointer-to-member and would like to know if there's a way to use it to initialise a struct in this context.

You cannot use designated initializers in the way you want to use them. However, you don't need to.

In your examples all members have different type, hence you don't even have to consider the value of the pointer:

union U {
    int    a;
    double b;
};

static constexpr inline auto a_ptr = &U::a;
static constexpr inline auto b_ptr = &U::b;

U make_U(int U::*) { return U{.a = 42}; }
U make_U(double U::*) { return U{.b = 42}; }

int main() {
    auto u1 = make_U(a_ptr);
    auto u2 = make_U(b_ptr);
}

Even if there are members with same type, you do not have to use the member pointer as designated initialzer directly:

union V {
  int    a;
  int b;
};

static constexpr inline auto a_ptr = &V::a;
static constexpr inline auto b_ptr = &V::b;

V make_V(int V::*p) { 
    return (p==a_ptr) ? V{.a = 42} : V{.b = 42};
}

int main() {
    auto u1 = make_V(a_ptr);
    auto u2 = make_V(b_ptr);
}

本文标签: cIs structunion initialisation with pointerstomembers possibleStack Overflow