struct merge_layer_flags_t {
bool use_interior_opacity = false;
bool use_master_opacity = false;
bool use_sheet_mask = false;
bool use_user_mask = false;
bool use_vector_mask = false;
bool use_content_mask = false;
bool use_source_ranges = false;
bool use_destination_ranges = false;
bool use_filter_mask = false;
};
{
merge_layer_flags_t flags;
flags.use_user_mask = true;
flags.use_content_mask = true;
auto [io, mo, sm, um, vm, cm, sr, dr, fm] = flags;
cout << io << ", " << mo << ", " << sm << ", " << um << ", " << vm << ", " << cm
<< ", " << sr << ", " << dr << ", " << fm << endl;
}
enum
and use structured bindings to unpack into bool
s?enum merge_layer_flags {
use_interior_opacity = 1 << 0,
use_master_opacity = 1 << 1,
use_sheet_mask = 1 << 2,
use_user_mask = 1 << 3,
use_vector_mask = 1 << 4,
use_content_mask = 1 << 5,
use_source_ranges = 1 << 6,
use_destination_ranges = 1 << 7,
use_filter_mask = 1 << 8
};
template <auto... I, class T>
constexpr auto extract_bits_a(T x) {
return tuple{static_cast<bool>(x & I)...};
}
{
merge_layer_flags flags =
static_cast<merge_layer_flags>(use_user_mask | use_content_mask);
auto [vm, um, cm] =
extract_bits_a<use_vector_mask, use_user_mask, use_content_mask>(flags);
cout << vm << ", " << um << ", " << cm << endl;
}
{
auto [x] = extract_bits_a<3>(7);
cout << x << endl;
}
ispow2()
is a C++20 function but we can implement ittemplate <class T>
constexpr bool ispow2(T x) {
return (x != 0) && !(x & (x - 1));
}
ispow2(3)
ispow2(4)
template <auto... I, class T>
constexpr auto extract_bits(T x) {
static_assert((ispow2(I) && ...));
return tuple{static_cast<bool>(x & I)...};
}
{
auto [x] = extract_bits<3>(7);
cout << x << endl;
}
input_line_22:3:5: error: static_assert failed
static_assert((ispow2(I) && ...));
^ ~~~~~~~~~~~~~~~~
input_line_25:3:16: note: in instantiation of function template specialization 'extract_bits<3, int>'
requested here
auto [x] = extract_bits<3>(7);
^
{
auto [x] = extract_bits<4>(7);
cout << x << endl;
}
enum class
or enum struct
, provides a strongly typed enumerationenum class choice { none, some, all };
enum bad_choice { none, some, all };
enum
declared within a class){
auto pick = choice::some;
auto bad_pick = some;
}
{
int bad_pick = some;
int pick = choice::some;
}
input_line_30:4:9: error: cannot initialize a variable of type 'int' with an rvalue of type 'choice'
int pick = choice::some;
^ ~~~~~~~~~~~~
enum class merge_layer {
use_interior_opacity = 1 << 0,
use_master_opacity = 1 << 1,
use_sheet_mask = 1 << 2,
use_user_mask = 1 << 3,
use_vector_mask = 1 << 4,
use_content_mask = 1 << 5,
use_source_ranges = 1 << 6,
use_destination_ranges = 1 << 7,
use_filter_mask = 1 << 8
};
{
auto flags = merge_layer::use_sheet_mask | merge_layer::use_vector_mask;
}
input_line_27:3:46: error: invalid operands to binary expression ('merge_layer' and 'merge_layer')
auto flags = merge_layer::use_sheet_mask | merge_layer::use_vector_mask;
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/sean-parent/miniconda3/envs/notebook/include/c++/v1/bitset:1059:1: note: candidate template ignored: could not match 'bitset<_Size>' against 'merge_layer'
operator|(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT
^
/Users/sean-parent/miniconda3/envs/notebook/include/c++/v1/valarray:4049:1: note: candidate template ignored: substitution failure [with _Expr1 = merge_layer, _Expr2
= merge_layer]: no type named 'value_type' in 'merge_layer'
operator|(const _Expr1& __x, const _Expr2& __y)
^
/Users/sean-parent/miniconda3/envs/notebook/include/c++/v1/valarray:4064:1: note: candidate template ignored: substitution failure [with _Expr = merge_layer]: no type
named 'value_type' in 'merge_layer'
operator|(const _Expr& __x, const typename _Expr::value_type& __y)
^
/Users/sean-parent/miniconda3/envs/notebook/include/c++/v1/valarray:4080:1: note: candidate template ignored: substitution failure [with _Expr = merge_layer]: no type
named 'value_type' in 'merge_layer'
operator|(const typename _Expr::value_type& __x, const _Expr& __y)
^
std::underlying_type_t<>
can be used to determine the type underlying any enum
type{
using underlying = underlying_type_t<merge_layer>;
auto flags = static_cast<merge_layer>(
static_cast<underlying>(merge_layer::use_sheet_mask) |
static_cast<underlying>(merge_layer::use_vector_mask));
}
<adobe/enum_ops.hpp>
which allows you to enable bitwise opsauto stlab_enable_bitmask_enum(merge_layer) -> std::true_type;
{
auto flags = merge_layer::use_sheet_mask | merge_layer::use_vector_mask;
auto [x] = extract_bits<merge_layer::use_sheet_mask>(flags);
cout << x << endl;
}
enum
typeenum class small_choice : std::int16_t {
none, some, all
};
{
cout << sizeof(small_choice) << endl;
}
enum very_small : std::uint8_t {
success, error
};
{
cout << sizeof(very_small) << endl;
}
int
int
unless an enumerator value cannot fit into an int
0
Replace unscoped enumerations with scoped enumerations
Use the <adobe/enum_ops.hpp>
(which may become <stlab/enum_ops.hpp>
soon) for
typedef
declarationsnamespace cpp98 {
typedef int some_type;
}
using some_type = int;
namespace cpp98 {
typedef int (*some_func)(int);
}
using some_func = int (*)(int);
typedef
, a type alias can be declared as a templatetemplate <class T>
using func_ptr = T (*)(T);
{
func_ptr<double> f = [](double x){ return x * x; };
cout << f(10);
}
namespace cpp98 {
template <class I>
auto distance(I f, I l) -> typename iterator_traits<I>::difference_type;
}
template <class I>
using difference_t = typename iterator_traits<I>::difference_type;
template <class I>
auto distance(I f, I l) -> difference_t<I>;
typename
used for a dependent type and replace it with template type alias[^,<] typename
to find an instanceinline
const
(or constexpr
) template variable is implicitly static
, one instance per translation unitinline
namespace {
template <class T>
inline constexpr T max_value = std::numeric_limits<T>::max();
} // namespace
{
auto x = max_value<int>;
cout << x << endl;
}
// header.hpp
namespace library {
template <class T>
class my_wizzy_type {
void member_function();
// ...
};
extern template class my_wizzy_type<int>;
} // namespace library
// code.cpp
#include "header.hpp"
namespace library {
template <class T>
void my_wizzy_type<T>::member_function() {
//...
}
template class my_wizzy_type<int>;
} // namespace library
__VA_ARGS__
holds argument list__VA_OPT__(
content
)
can be used in the replacement (C++20)__VA_ARGS__
is not empty __VA_OPT__(
content
)
is replaced with content
__VA_OPT__(
content
)
expands to nothing#define ARRAY(...) \
int array[] = { __VA_ARGS__ }
{
ARRAY(5, 3);
for (const auto& e : array) cout << e << endl;
}
__VA_ARGS__
quotes the entire replacement#define SHOW(...) \
#__VA_ARGS__
SHOW(10, 42.5, x)
std::vector<>
std::vector<>