Skip to content

Latest commit

 

History

History
150 lines (138 loc) · 10 KB

README.md

File metadata and controls

150 lines (138 loc) · 10 KB

Circle member traits

Member traits is a Circle extension that makes using numeric_limits and type_traits fun and easy. These constants and types are accessed like non-static data members on a type.

traits1.cxx

#include <limits>
#include <type_traits>
#include <array>
#include <list>
#include <iostream>

struct base_t { virtual void func() = 0; };
struct derived_t final : base_t { virtual void func() override { } };
enum enum_t : short { };

int main() {
  // Access all numeric_traits.
  std::cout<< float.max        << ", "<< float.epsilon<< "\n";
  std::cout<< double.max       << ", "<< double.epsilon<< "\n";
  std::cout<< (long double).max<< ", "<< (long double).epsilon<< "\n";

  // Access type_traits.
  static_assert(void.is_void);
  static_assert(std::array<float, 5>.is_aggregate);
  static_assert(!std::list<char>.is_aggregate);
  static_assert((float[][2][3]).is_unbounded_array);
  static_assert((long(std::list<char>::*)).is_member_object_pointer);
  static_assert(derived_t.is_final);
  static_assert(base_t.is_polymorphic);
  static_assert(enum_t.is_enum);

  // Mutate types using type_traits.
  static_assert(std::is_same_v<
    const int*.remove_pointer.make_unsigned,
    const unsigned int
  >);

  static_assert(std::is_same_v<
    enum_t.underlying_type.add_rvalue_reference,
    short&&
  >);

  static_assert(std::is_same_v<
    char(.decay)[3],      // This is how to write (char[3]).decay.
    char*
  >);
}
$ circle -std=c++20 traits1.cxx && ./traits1
3.40282e+38, 1.19209e-07
1.79769e+308, 2.22045e-16
1.18973e+4932, 1.0842e-19

There are three kinds of traits supported with this extension:

  1. Value members of std::numeric_limits. These are only supported for types that have a partial or explicit specialization of the std::numeric_limits class template. Attempting to accessa numeric limit on a type that doesn't have a specialization (by default, any non-builtin or non-arithmetic type) raises a SFINAE failure. The has_numeric_limits trait indicates if the type on the left-hand side has a specialization.

  2. Value members of std::type_traits. These are supported for all C++ types. Some of these traits require C++20 or even C++23 headers.

  3. Type aliases of std::type_traits. These are conditionally supported. Since types are parsed differently from values, the .member-trait-name syntax applies like a ptr-operator. It has left-to-right associativity. Chain them together to perform complex type transformations. Note that if you want to apply a type alias member trait to a declarator that has a noptr-operator, you'll need to use C++'s quite obscure spiral rule for declarations. char(.decay)[3] decays the type char[3]. We can't simply write char[3].decay, because that is ungrammatical in C++.