Why is std::is_pod deprecated in C++20?
POD is being replaced with two categories that give more nuances. The c++ standard meeting in november 2017 had this to say about it:
Deprecating the notion of “plain old data” (POD). It has been replaced with two more nuanced categories of types, “trivial” and “standard-layout”. “POD” is equivalent to “trivial and standard layout”, but for many code patterns, a narrower restriction to just “trivial” or just “standard layout” is appropriate; to encourage such precision, the notion of “POD” was therefore deprecated. The library trait is_pod has also been deprecated correspondingly.
For simple data types use the is_standard_layout
function, for trivial data types (such as simple structs) use the is_trivial
function.
Struct with a volatile member no longer a POD according to MSVC
From the Microsoft documentation:
When a class or struct is both trivial and standard-layout, it is a POD (Plain Old Data) type.
It later describes literal types, including the following condition:
Additionally, all its non-static data members and base classes must be literal types and not volatile.
There is no mention of "volatile" anywhere else on the page.
This all matches what we find in the standard.
Therefore, I conclude it's a compiler bug.
getStuff() generates an error because it attempts to return a type that is not compatible with the C calling convention.
Actually, this is just a warning (C4190), which you could disable, if you wanted. Visual Studio on x86_64 only has one calling convention (described here). Your code will still work fine. VS is just warning you that the type won't work if you actually try to use it in C. extern "C"
does not mean compiling as C.
However, it is true that getting this warning suggests the bug is indeed in the compiler, rather than simply in the implementation of std::is_pod
.
Also, I would recommend avoiding POD terminology and the std::is_pod
trait in new code, since they are deprecated from C++20.
The extern "C" part is in a C header that needs to stay as is. How could I use it from C++?
Anything that doesn't actually require the type to fit VS's definition of "POD", type trait notwithstanding, should be fine.
How do I use std::is_pod in a template argument?
You need to use std::enable_if
to use the value from std::is_pod
in a SFINAE context. That would look like
// only enable this template if Z is a pod type
template <class Z, std::enable_if_t<std::is_pod_v<Z>, bool> = true>
void x()
{
std::cout << "yep" << std::endl;
}
// only enable this template if Z is not a pod type
template <class Z, std::enable_if_t<!std::is_pod_v<Z>, bool> = true>
void x()
{
std::cout << "nope" << std::endl;
}
Do note that std::is_pod
is deprecated in C++17 and has been removed from C++20.
What trait / concept can guarantee memsetting an object is well defined?
There is technically no object property in C++ which specifies that user code can legally memset
a C++ object. And that includes POD, so if you want to be technical, your code was never correct. Even TriviallyCopyable is a property about doing byte-wise copies between existing objects (sometimes through an intermediary byte buffer); it says nothing about inventing data and shoving it into the object's bits.
That being said, you can be reasonably sure this will work if you test is_trivially_copyable
and is_trivially_default_constructible
. That last one is important, because some TriviallyCopyable types still want to be able to control their contents. For example, such a type could have a private int
variable that is always 5, initialized in its default constructor. So long as no code with access to the variable changes it, it will always be 5. The C++ object model guarantees this.
So you can't memset
such an object and still get well-defined behavior from the object model.
Should we serialize std::chrono::duration class or is it P.O.D. (Plain Old Data) and no serialization is needed?
Your code "proves" only one thing: that the implementation you ran it on implemented duration
such that it is trivially copyable and standard layout. Nothing in the standard requires it to be so, so any other implementation (including later versions of the same library) can freely change the rules.
Now, you can do some if constexpr
/enable_if
or similar gymnastics, so that if an implementation provides trivial copyability, you use that ability rather than "serializing" it. But you can't assume that this will always be the case (unless you are working in an environment where you know you will always use a particular library); you can merely take advantage of it where available.
What are POD types in C++?
POD stands for Plain Old Data - that is, a class (whether defined with the keyword struct
or the keyword class
) without constructors, destructors and virtual members functions. Wikipedia's article on POD goes into a bit more detail and defines it as:
A Plain Old Data Structure in C++ is an aggregate class that contains only PODS as members, has no user-defined destructor, no user-defined copy assignment operator, and no nonstatic members of pointer-to-member type.
Greater detail can be found in this answer for C++98/03. C++11 changed the rules surrounding POD, relaxing them greatly, thus necessitating a follow-up answer here.
Related Topics
Reinterpret_Cast Between Char* and Std::Uint8_T* - Safe
C++ How to Allocate Memory Dynamically on Stack
C++ Concatenating _File_ and _Line_ MACros
How to Use Signal Inside a C++ Class
How to Write a Stateful Allocator in C++11, Given Requirements on Copy Construction
Differencebetween a .Cpp File and a .H File
How to Count Lines of a File in C++
How to Prevent Non-Specialized Template Instantiation
Maximum Number of Parameters in Function Declaration
Sort Based on Multiple Things in C++
What's the Best Way to Check If a File Exists in C++? (Cross Platform)
"Apientry _Twinmain" and "Winapi Winmain" Difference
Where in Memory Is Vtable Stored
Name of Process for Active Window in Windows 8/10
Why the Size of a Pointer to a Function Is Different from the Size of a Pointer to a Member Function