Bootstrap

2411C++,学习C++提示2

C++26包索引

template<auto N> consteval auto nth(auto... ts) { return ts...[N]; }
static_assert(1 == nth<0>(1, 2, 3));
static_assert(2 == nth<1>(1, 2, 3));
static_assert(3 == nth<2>(1, 2, 3));

C++26包索引的第1和最后

template <size_t Index, class T0, class... Types>
constexpr decltype(auto) nth(T0&& p0, Types&&... pack) noexcept
{
   if constexpr (0 == Index)
       return std::forward<T0>(p0);
   else
       return nth<Index-1>(std::forward<Types>(pack)...);
}
 
consteval auto first(auto... ts) {
    return nth<0>(ts...);
}

consteval auto last(auto... ts) {
    return nth<sizeof...(ts) - 1>(ts...);
}
static_assert(1 == first(1, 2, 3));
static_assert(3 == last(1, 2, 3));

平映

int main() {
  stdext::flat_map<int, int> fm{};
  fm.emplace(1, 2);
  fm.emplace(3, 4);
  assert(fm.size() == 2);
  assert(fm[1]==2 and fm[2]==3);
}

无唯一地址

template<class> struct box{};

struct unique {
    [[no_unique_address]] box<int> _1;
    [[no_unique_address]] box<bool> _2;
};
static_assert(sizeof(unique)==1);

struct no_unique {
    [[no_unique_address]] box<int> _1;
    [[no_unique_address]] box<int> _2;
};

static_assert(sizeof(no_unique)!=1);

是独特的

template <class T> struct box {};

template <class... Ts> struct unique;

template <>
struct unique<> {};

template <class T, class ...Args>
struct unique<T, Args ...> : public unique<Args ...> {
    constexpr explicit unique(T&& t, Args&&... args) : unique<Args...>(args ...) {

    }
    [[no_unique_address]] box<T> t_;
};

template <class... Ts>
constexpr auto is_unique = (sizeof(unique<Ts...>) == 1);
template <typename T>
struct empty_wrap { };

template <typename T, typename = decltype([]() {})>
struct unique_empty_box {
    [[no_unique_address]] empty_wrap<T> e;
};

template <typename... Ts>
struct empty_type_pack : public unique_empty_box<Ts>... { };

template <typename... Ts>
constexpr bool is_unique = sizeof(empty_type_pack<Ts...>) == 1;
template <class>
struct box {
    box() = delete;
};
template <class... Ts>
struct S;
template <>
struct S<> {};
template <class T, class... Ts>
struct S<T, Ts...> : S<Ts...> {
    [[no_unique_address]] box<T> _;
};

template <class... Ts>
constexpr auto is_unique = sizeof(S<Ts...>) == 1;

线本常初化

extern constinit thread_local int var;
auto fn() { return var; }

区间串视

constexpr std::string text = "Hello, World!";
constexpr std::string_view view(text.c_str() + 7, 5);
static_assert(view == std::string_view{"World"});

显式串视缓冲

template<auto N>
struct buffer; // TODO

constexpr buffer<42> b;
static_assert(42 == std::string_view{b}.size());
static_assert(&b.data[0] == std::string_view{b}.begin());
static_assert(&b.data[42] == std::string_view{b}.end());
template <auto N>
struct buffer {
    constexpr buffer() {}
    constexpr char const* begin() const { return data; }
    constexpr char const* end() const { return data + N; }
    constexpr operator std::basic_string_view<char>() const {
        return std::basic_string_view<char>(begin(), end());
    }
    char data[N]{};
};

标::访问

template<class... Ts>
struct inc {
    std::variant<Ts...> v{};

    auto operator++() {
        std::visit([&](auto& v) { ++v; }, v);
    }

    template<class T>
    operator T() const {
        T result{};
        std::visit(
            overloaded{
                [&](T v) { result = v; },
                [](auto&&) {}
            }
        , v);
        return result;
    }
};

auto visit(std::int16_t size, std::int32_t iterations) {
    auto it = inc<std::int8_t, std::int16_t, std::int32_t>{size};

    for (auto i = 0; i < iterations; ++i, ++it)
        ;

    return std::int16_t(it);
}

实现:

template<class F, class V, class R, std::size_t N, std::size_t Size>
constexpr auto visit_impl([[maybe_unused]] F&& f, [[maybe_unused]] V&& v) -> R {
  if constexpr (N < Size) {
    switch (v.index()) {
      default:
        return visit_impl<F, V, R, N+1, Size>(std::forward<F>(f), std::forward<V>(v));
      case N:
        return std::forward<F>(f)(std::get<N>(std::forward<V>(v)));
    }
  } else {
    __builtin_unreachable();
  }
}

template<class F, class V, template<class...> class T, class... Ts>
auto result_type(T<Ts...>&&) ->
  std::common_type_t<decltype(std::declval<F>()(std::get<Ts>(std::declval<V>())))...>;

template<class F, class V, template<class...> class T, class... Ts>
auto result_type(T<std::monostate, Ts...>&&) ->
  std::common_type_t<decltype(std::declval<F>()(std::get<Ts>(std::declval<V>())))...>;

template<class F, class V>
constexpr decltype(auto) visit(F&& f, V&& v) {
  using variant_t = std::remove_const_t<std::remove_reference_t<V>>;
  constexpr auto size = std::variant_size_v<variant_t>;
  static_assert(size > 0, "Empty variant is not supported!");
  using result_t = decltype(result_type<F, V>(std::declval<variant_t>()));
  return visit_impl<F, V, result_t, 0u, size>(std::forward<F>(f), std::forward<V>(v));
}

C++26可变友

class FriendClass;

class MyClass {
    friend class FriendClass;

public:
    constexpr MyClass(int data) : privateData(data) {}

private:
    int privateData;
};

struct FriendClass {
    constexpr auto accessPrivateData(const MyClass& obj) const {
        return obj.privateData;
    }
};

constexpr MyClass obj{42};
constexpr FriendClass friend_obj{};
static_assert(42 == friend_obj.accessPrivateData(obj));

扩展可变友类

template <class... Ts>
class MyClass {
   friend Ts...;

   public:
    constexpr explicit MyClass(int data) : privateData(data) {}

   private:
    int privateData{};
};

template<auto>
struct FriendClass {
    constexpr auto accessPrivateData(const auto& obj) const {
        return obj.privateData;
    }
};

constexpr MyClass<FriendClass<0>, FriendClass<1>, FriendClass<2>> obj{42};
constexpr FriendClass<0> friend_obj0{};
constexpr FriendClass<1> friend_obj1{};
constexpr FriendClass<2> friend_obj2{};

static_assert(42 == friend_obj0.accessPrivateData(obj));
static_assert(42 == friend_obj1.accessPrivateData(obj));
static_assert(42 == friend_obj2.accessPrivateData(obj));

原位向量

int main() {
    std::inplace_vector<int, 2> v{};
    assert(v.empty());

    v.push_back(1);
    assert(1 == v.size());

    v.push_back(2);
    assert(2 == v.size());

    v.push_back(3); // throws
}

实现

template <class T, auto Size>
struct inplace_vector {
    constexpr void push_back(T value) { data_[index_++] = value; }
    constexpr const auto& operator[](auto index) const { return data_[index]; }
    constexpr auto size() const { return index_; }
    constexpr auto clear() { index_ = {}; }

   private:
    std::array<T, Size> data_{};
    std::size_t index_{};
};
template <class T, auto Size>
class inplace_vector {
   public:
    constexpr T& push_back(const T& t) {
        if (size_ == Size) {
            throw std::bad_alloc();
        }
        return arr_[size_++].emplace(t);
    }

    constexpr std::size_t size() const { return size_; }

    constexpr T& operator[](std::size_t idx) { return *arr_[idx]; }

   private:
    std::array<std::optional<T>, Size> arr_;
    std::size_t size_ = 0;
};

聚集是命名元组

#include <tuple>

struct foo {
    int i{};
    bool b{};
    float f{};
};

constexpr auto f  = foo{.i = 42, .b = true, .f = 4.2f};
static_assert(42 == std::get<0>(f) and std::get<1>(f) and 4.2f == std::get<2>(f));

聚集的取

template <typename T, std::size_t I, typename = void>
struct has_get : std::false_type {};
template <typename T, std::size_t I>
struct has_get<T, I, std::void_t<decltype(std::get<I>(std::declval<T>()))>>
    : std::true_type {};

namespace std {
template <typename T>
concept DoesNotHaveGetConcept = requires(T t) { !has_get<T, 0>::value; };
namespace mp = boost::mp;
template <std::size_t I>
constexpr auto get(DoesNotHaveGetConcept auto s) {
    return std::get<I>(mp::reflection::to_tuple(s));
}
}  // namespace std

更多数学常式

#include <cmath>
constexpr auto positive = std::abs(-2);
static_assert(positive == 2);
template <char... Cs>
[[nodiscard]] constexpr auto operator""_number() {
    return []<auto... Is, class T = int>(std::index_sequence<Is...>) {
        return std::integral_constant<
            T, (((Cs - '0') * T(std::pow(T(10), sizeof...(Is) - Is - 1))) +
                ...)>{};
    }
    (std::make_index_sequence<sizeof...(Cs)>{});
}

#include <cmath>

template <char... Cs>
[[nodiscard]] constexpr auto operator""_number();

static_assert(0 == 0_number);
static_assert(42 == 42_number);
static_assert(123 == 123_number);

template <char... Cs>
[[nodiscard]] constexpr auto operator""_number() {
    int result = 0;
    ((result = result * 10 + (Cs - '0')), ...);
    return result;
}

C++26常式从空*转换

struct foo{};
constexpr auto f1 = foo{};
constexpr auto ptr = static_cast<const void*>(&f1);
constexpr auto f2 = static_cast<const foo*>(ptr); // okay in C++26

常式擦除

struct Animal_View {
    const void *animal;
    std::string_view (*speak_func)(const void *animal);

    template <class Animal>
    Animal_View(const Animal &animal)
        : animal(&animal), speak_func([](const void *animal) {
              return static_cast<const Animal *>(animal)->speak();
          }) {}

    constexpr std::string_view speak() { return speak_func(animal); }
};
struct Sheep {
    constexpr std::string_view speak() const noexcept { return "Baaaaaa"; }
};

struct Cow {
    constexpr std::string_view speak() const noexcept { return "Mooo"; }
};

// TODO Animal_View

std::string_view do_speak(Animal_View av) { return av.speak(); }

int main() {
    using namespace boost::ut;

    "constexpr cast from void*"_test = [] {
        should("say Mooo for cow") = [] {
            constexpr Cow cow;
            auto result = do_speak(cow);
            expect(std::string_view{"Mooo"} == result);
        };

        should("say Baaaaaa for sheep") = [] {
            constexpr Sheep sheep;
            auto result = do_speak(sheep);
            expect(std::string_view{"Baaaaaa"} == result);
        };
    };
}

成员访问

// C++23
std::visit(overload{
  [](int i){ std::print("i={}\n", i); },
  [](std::string s){ std::print("s={:?}\n", s); }
}, value);

// C++26
value.visit(overload{
  [](int i){ std::print("i={}\n", i); },
  [](std::string s){ std::print("s={:?}\n", s); }
});

变量成员访问

// TODO: variant

int main() {
    constexpr variant<int, double, float> value = 42;

    static_assert(42 == value.visit(overload{
        [](int i) { return i; },
        [](auto)  { return 0; }
    }));
}
template <class... Ts>
struct overload : Ts... {
    using Ts::operator()...;
};
template <class... Ts>
overload(Ts...) -> overload<Ts...>;

template <class... Ts>
struct variant : std::variant<Ts...> {
    using std::variant<Ts...>::variant;

    constexpr auto visit(auto f) const { return std::visit(f, *this); }
};
;