3

I'm looking for solution to disable using as a template parameter structures that are POD (or say copyable) but has pointers. I'm going to send them over network. E.g.

// good
struct S1 {
    int x;
    S1() : x( 42 ) {} // I know that it's not a POD, but I know, that I can send S1 over network
};
// bad
struct S2 {
    int *x;
};

template<typename POD>
class ToNetwork {
    //static_assert( std::is_trivially_copyable< POD >::value, "Type must be POD" );
    static_assert( std::is_standard_layout< POD >::value, "Type must be POD" );
    POD m_payload;
};
ToNetwork< S1 > s1;
ToNetwork< S2 > s2; // should fail, but not((

Either is_trivially_copyable or is_standard_layout say that both structures are good.

borisbn
  • 4,988
  • 25
  • 42
  • not sure if this is possible in general to detect automatically. Suppose you have a `struct S3 { some_iterator_type it; }`. or `struct S4 { size_t index_into_some_container; };` – 463035818_is_not_an_ai Sep 23 '21 at 08:33
  • this might help: https://stackoverflow.com/questions/17660095/iterating-over-a-struct-in-c – 463035818_is_not_an_ai Sep 23 '21 at 08:34
  • Notice that you have normally to handle each member separately (at least to handle endianess), so you cannot simply `memcpy` the structure anyway. – Jarod42 Sep 23 '21 at 08:41
  • @Jarod42 I have a `template` and want to `memcpy` it. I do not know about members of `POD` – borisbn Sep 23 '21 at 08:59
  • @463035818_is_not_a_number I saw MSVC's implementation of `iterator` - it has pointers. That's why if I'll find solution, then iterators wouldn't be a problem. If I send static array ([42]) and index inside it would be good for me – borisbn Sep 23 '21 at 09:11
  • I meant that serialization (over network) is not as simple as memcpy. So using some kind of library about reflection might help. (then you can also detect pointer, custom class, ...). – Jarod42 Sep 23 '21 at 09:13
  • are you in control of `S1`, `S2` etc ? If yes you can give them a member alias/tag or speicalize your own trait `is_trivially_serializable` – 463035818_is_not_an_ai Sep 23 '21 at 09:34

1 Answers1

0

This is partly a frame challenge answer: to correctly serialize something, it is anyway not sufficient to have only non-pointer trivial members.

Even if you currently only talk to peers on the same platform, depending on this is brittle (ie, you'll have to document your endianness and data sizes when someone wants to connect with an ARM/RISC/M1/other device).

Further, the padding and alignment requirements of in-memory and on-wire types rarely agree. You tend to end up either (de)serializing member-by-member, or writing a packed/misaligned overlay struct which is less efficient for in-memory use (and is also non-portable).

This means in practice you're going to declare dedicated types for sending over the network - either ones with their own (de)serialize methods, or ones with some metadata, or ones with __attribute__((packed)), or whatever. Since they're dedicated to this, it's trivial to give them a member or nested type for your SFINAE to detect directly.

Useless
  • 64,155
  • 6
  • 88
  • 132
  • I do have a library (internal for our team) that exchanges over network by this structures (over 300 types). The library succesfully uses template like `ToNetwork` from question. I have a guarantee that platform will be the same. I just want to modify this template to further structures for not to shoot in my leg)) – borisbn Sep 23 '21 at 14:18
  • I don't think there's a way of doing this directly, so you'll just have to catch it in code review or testing. Over 300 custom message types is a lot! – Useless Sep 23 '21 at 17:44