flags: Utilize underlying_type for more expressiveness

Change-Id: Ie57b3a17d8eccd9c7701f7679102395f96670607
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include-dl/stdplus/dl.hpp b/include-dl/stdplus/dl.hpp
index 24044c1..4c653da 100644
--- a/include-dl/stdplus/dl.hpp
+++ b/include-dl/stdplus/dl.hpp
@@ -23,15 +23,15 @@
     DeepBind = RTLD_DEEPBIND,
 };
 
-class DlOpenFlags : public stdplus::BitFlags<int, DlOpenFlag>
+class DlOpenFlags : public stdplus::BitFlags<DlOpenFlag>
 {
   public:
     inline DlOpenFlags(DlOpenType type) :
-        BitFlags<int, DlOpenFlag>(static_cast<int>(type))
+        BitFlags<DlOpenFlag>(std::to_underlying(type))
     {}
 
-    inline DlOpenFlags(BitFlags<int, DlOpenFlag> flags) :
-        BitFlags<int, DlOpenFlag>(flags)
+    inline DlOpenFlags(BitFlags<DlOpenFlag> flags) :
+        BitFlags<DlOpenFlag>(flags)
     {}
 };
 
diff --git a/include-fd/stdplus/fd/create.hpp b/include-fd/stdplus/fd/create.hpp
index 9bd7ede..81ebfde 100644
--- a/include-fd/stdplus/fd/create.hpp
+++ b/include-fd/stdplus/fd/create.hpp
@@ -41,16 +41,14 @@
     Trunc = O_TRUNC,
 };
 
-class OpenFlags : public BitFlags<int, OpenFlag>
+class OpenFlags : public BitFlags<OpenFlag>
 {
   public:
     inline OpenFlags(OpenAccess access) :
-        BitFlags<int, OpenFlag>(static_cast<int>(access))
+        BitFlags<OpenFlag>(std::to_underlying(access))
     {}
 
-    inline OpenFlags(BitFlags<int, OpenFlag> flags) :
-        BitFlags<int, OpenFlag>(flags)
-    {}
+    inline OpenFlags(BitFlags<OpenFlag> flags) : BitFlags<OpenFlag>(flags) {}
 };
 
 DupableFd open(const_zstring pathname, OpenFlags flags, mode_t mode = 0);
diff --git a/include-fd/stdplus/fd/intf.hpp b/include-fd/stdplus/fd/intf.hpp
index c4e2d7b..7f448c8 100644
--- a/include-fd/stdplus/fd/intf.hpp
+++ b/include-fd/stdplus/fd/intf.hpp
@@ -24,7 +24,7 @@
     Trunc = MSG_TRUNC,
     WaitAll = MSG_WAITALL,
 };
-using RecvFlags = BitFlags<int, RecvFlag>;
+using RecvFlags = BitFlags<RecvFlag>;
 
 enum class SendFlag : int
 {
@@ -36,7 +36,7 @@
     NoSignal = MSG_NOSIGNAL,
     OutOfBounds = MSG_OOB,
 };
-using SendFlags = BitFlags<int, SendFlag>;
+using SendFlags = BitFlags<SendFlag>;
 
 enum class Whence : int
 {
@@ -71,7 +71,7 @@
 {
     CloseOnExec = FD_CLOEXEC,
 };
-using FdFlags = BitFlags<int, FdFlag>;
+using FdFlags = BitFlags<FdFlag>;
 
 enum class FileFlag : int
 {
@@ -81,7 +81,7 @@
     NoAtime = O_NOATIME,
     NonBlock = O_NONBLOCK,
 };
-using FileFlags = BitFlags<int, FileFlag>;
+using FileFlags = BitFlags<FileFlag>;
 
 enum class ProtFlag : int
 {
@@ -89,7 +89,7 @@
     Read = PROT_READ,
     Write = PROT_WRITE,
 };
-using ProtFlags = BitFlags<int, ProtFlag>;
+using ProtFlags = BitFlags<ProtFlag>;
 
 enum class MMapAccess : int
 {
@@ -101,16 +101,14 @@
 {
 };
 
-class MMapFlags : public BitFlags<int, MMapFlag>
+class MMapFlags : public BitFlags<MMapFlag>
 {
   public:
     inline MMapFlags(MMapAccess access) :
-        BitFlags<int, MMapFlag>(static_cast<int>(access))
+        BitFlags<MMapFlag>(std::to_underlying(access))
     {}
 
-    inline MMapFlags(BitFlags<int, MMapFlag> flags) :
-        BitFlags<int, MMapFlag>(flags)
-    {}
+    inline MMapFlags(BitFlags<MMapFlag> flags) : BitFlags<MMapFlag>(flags) {}
 };
 
 class MMap;
diff --git a/include/stdplus/flags.hpp b/include/stdplus/flags.hpp
index a5678f3..4fdd511 100644
--- a/include/stdplus/flags.hpp
+++ b/include/stdplus/flags.hpp
@@ -1,44 +1,52 @@
 #pragma once
+#include <stdplus/concepts.hpp>
+
+#include <concepts>
+#include <type_traits>
 #include <utility>
 
 namespace stdplus
 {
 
-template <typename Int, typename Flag = Int>
+template <Enum T, std::integral I = std::underlying_type_t<T>>
 class BitFlags
 {
   public:
-    inline explicit BitFlags(Int val = 0) noexcept : val(val) {}
+    using type = T;
+    using underlying = I;
 
-    inline BitFlags& set(Flag flag) & noexcept
+    inline BitFlags() noexcept : val(0) {}
+    explicit inline BitFlags(underlying val) noexcept : val(val) {}
+
+    inline BitFlags& set(type flag) & noexcept
     {
-        val |= static_cast<Int>(flag);
+        val |= std::to_underlying(flag);
         return *this;
     }
-    inline BitFlags&& set(Flag flag) && noexcept
+    inline BitFlags&& set(type flag) && noexcept
     {
-        val |= static_cast<Int>(flag);
+        val |= std::to_underlying(flag);
         return std::move(*this);
     }
 
-    inline BitFlags& unset(Flag flag) & noexcept
+    inline BitFlags& unset(type flag) & noexcept
     {
-        val &= ~static_cast<Int>(flag);
+        val &= ~std::to_underlying(flag);
         return *this;
     }
-    inline BitFlags&& unset(Flag flag) && noexcept
+    inline BitFlags&& unset(type flag) && noexcept
     {
-        val &= ~static_cast<Int>(flag);
+        val &= ~std::to_underlying(flag);
         return std::move(*this);
     }
 
-    explicit inline operator Int() const noexcept
+    explicit inline operator underlying() const noexcept
     {
         return val;
     }
 
   private:
-    Int val;
+    underlying val;
 };
 
 } // namespace stdplus