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

发布于:2024-11-29 ⋅ 阅读:(44) ⋅ 点赞:(0)

C++26绑定作为条件

struct foo {
  int a{};
  int b{};
  constexpr operator bool() const { return a != b; } // implicit condition
};

auto test = [](auto... ts) {
  if (auto [a, b] = foo{ts...}) { // structure binding as condition
    return true;
  }
  return false;
};

static_assert(test(1, 2));
static_assert(not test(1, 1));

C++26常式原地新

static_assert([] {
  std::array<int, 1024> storage{};
  auto ptr = new (storage.data()) int{42};
  return 42 == *ptr;
}());

static_assert([] {
  std::array<int, 1024> storage{};
  auto ptr = std::construct_at<int>(storage.data(), 42);
  return 42 == *ptr;
}());

simd

int main() {
  std::array<char, 8> storage{1, 2, 3, 4, 5, 6, 7, 8};
  std::experimental::fixed_size_simd<char, 8> data{storage.begin(), std::experimental::element_aligned};
  std::experimental::fixed_size_simd_mask<char, 8> values = (data == 7);
  std::cout << std::experimental::any_of(values) << std::endl;
}

C++位集

#include <bitset>
constexpr std::bitset<8> bs{0b00000001};
static_assert(bs.test(0));
static_assert(not bs.test(1));

位集逆转

template<auto Size>
constexpr auto reverse(std::bitset<Size> bs) {
  std::bitset<Size> r{};
  for (auto i = 0; i < bs.size(); ++i) {
    r[r.size()-i-1] = bs[i];
  }
  return r;
}

static_assert(0b10000000 == reverse(std::bitset<8>{0b00000001}));
static_assert(0b10000001 == reverse(std::bitset<8>{0b10000001}));
static_assert(0b11100001 == reverse(std::bitset<8>{0b10000111}));

C++静态反射

template<class...> struct type_list { };

using type = typename [: 
// splicer - produces an expression
      std::meta::substitute(^type_list, 
// not instantiated
          std::array{^int, ^float, ^short} 
// std::array{meta::info}
    | std::views::reverse // stl.ranges
    | std::views::drop(1)
    | std::ranges::to<std::vector>()
    )
:];

static_assert(typeid(type) == typeid(type_list<float, int>));

静态反射过滤有值类型

template<class...> struct type_list { };

template<class T>
concept has_value = requires(T t) { t.value; };

template<class... Ts>
using filter = typename [: std::meta::substitute(^type_list,
    std::array{^Ts...}
  | std::views::filter([](auto m) { return test_type(^has_value, m); })
  | std::ranges::to<std::vector>())
:];

struct foo { int value; };
struct bar { };

static_assert(typeid(filter<int>) == typeid(type_list<>));
static_assert(typeid(filter<foo>) == typeid(type_list<foo>));
static_assert(typeid(filter<bar, foo>) == typeid(type_list<foo>));
static_assert(typeid(filter<int, double, foo, bar>) == typeid(type_list<foo>));
static_assert(typeid(filter<int, double, bar>) == typeid(type_list<>));

C++过时接口的原因

void newapi();
void oldapi() = delete("旧接口过时了,请用newapi()");

int main () {
  oldapi();
}

错误用法报错

template<class T> constexpr T* addressof(T& r) noexcept { return &r; }
template<class T> const T* addressof(const T&&) = delete("不能取右值地址.");

int main() {
  int i{};
  addressof(i);     // okay
  addressof(int{});
  // error: "Cannot take address of rvalue."
}

span.at

std::array<int, 42> storage{};
const auto span = std::span(storage);
(void)span.at(0); // okay
(void)span.at(storage.size()); // throws

无异与有异常不同

struct span_at {
  constexpr explicit span_at(std::span<const int> span) : span_{span} { }

  [[nodiscard]] constexpr auto operator()(auto&& fn, auto index) {
    if constexpr(noexcept(fn(span_[index]))) {
      return fn(span_[index]);
    } else {
      return fn(span_.at(index));
    }
  }

 private:
  std::span<const int> span_{};
};

硬件推导大小

#include <new>
static_assert(64u == std::hardware_destructive_interference_size); // x86-64

缓存对齐数组

constexpr auto cache_aligned_array(auto... args) {
    struct alignas(std::hardware_destructive_interference_size) 
      : decltype(std::array{args...}) { } array {args...};
    return array;
};

static_assert(std::hardware_destructive_interference_size == alignof(cache_aligned_array(1, 2, 3)));

显式管理生命期

std::array<std::byte, 1024> data{};
std::fill(std::begin(data), std::end(data), std::byte{42});

struct foo {
  std::uint8_t x;
  std::uint8_t y;
};

auto* f = std::start_lifetime_as<foo>(std::data(data));
std::cout << f->x << f->y; // prints 4242

template<class T> auto start_lifetime_as(void* p) noexcept -> T* {
  const auto bytes = new (p) std::byte[sizeof(T)];
  const auto ptr = reinterpret_cast<T*>(bytes);
  (void*)ptr;
  return ptr;
}

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

  "start_lifetime_as"_test = [] {
    std::array<std::byte, 1024> data{};
    std::fill(std::begin(data), std::end(data), std::byte{42});
  
    struct foo {
      std::uint8_t x;
      std::uint8_t y;
    };
  
    auto* f = start_lifetime_as<foo>(std::data(data));
    expect(42_i == f->x);
    expect(42_i == f->y);
  };
}

块流

#include <spanstream>

int main() {
    char output[30]{};
    std::ospanstream os{std::span<char>{output}};
    os << 10 << 20 << 30;
    auto const sp = os.span();
    std::cout << sp.size(); // prints 6
    std::cout << std::string(sp.data(),sp.size()); // prints 102030
}

块流实现连接串

[[nodiscard]] constexpr auto strcat(auto&&... args) {
    char buf[256]{};
    std::ospanstream oss{std::span{buf}};
    ((oss << args), ...);
    const auto span = oss.span();
    return std::string{span.data(), span.size()};
}

原位置取成员名

namespace detail {
template <class, auto>
[[nodiscard]] consteval auto member_name() -> std::string_view {
    return std::source_location::current().function_name();
}
template <class T> extern const T external;
consteval auto get(auto& obj) {
    auto& [p1] = obj;
    return &p1;
}
} // namespace deatil

template <class T>
constexpr auto member_name = detail::member_name<T, detail::get(detail::external<T>)>();

struct foo {
  int bar;
};

static_assert(member_name<foo>.find("bar") != std::string_view::npos);

从构转元组

template <std::size_t N>
class fixed_string final {
   public:
    constexpr explicit(true) fixed_string(const auto... cs) : data{cs...} {}
    constexpr explicit(false) fixed_string(const char (&str)[N + 1]) {
        std::copy_n(str, N + 1, std::data(data));
    }
    [[nodiscard]] constexpr auto operator<=>(const fixed_string&) const =
        default;
    [[nodiscard]] constexpr explicit(false) operator std::string_view() const {
        return {std::data(data), N};
    }
    [[nodiscard]] constexpr auto size() const -> std::size_t { return N; }
    std::array<char, N + 1> data{};
};

template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;

template <fixed_string Name, class T>
struct named {
    static constexpr auto name = Name;
    T value{};
};

struct any_type {
    template <class T>
    constexpr operator T();
};

template <class TPtr>
struct ptr {
    const TPtr* ptr;
};

namespace detail {
template <class T>
extern const T external;
struct any_type {
    template <class T>
    constexpr operator T();
};
template <class TPtr>
struct ptr {
    const TPtr* ptr;
};

template <auto N, class T>
[[nodiscard]] constexpr auto nth_ptr(T&& t) {
    if constexpr (requires { T{any_type{}, any_type{}, any_type{}}; }) {
        auto&& [p1, p2, p3] = t;
        if constexpr (N == 0) return ptr<decltype(p1)>{&p1};
        if constexpr (N == 1) return ptr<decltype(p2)>{&p2};
        if constexpr (N == 2) return ptr<decltype(p3)>{&p3};
    } else if constexpr (requires { T{any_type{}, any_type{}}; }) {
        auto&& [p1, p2] = t;
        if constexpr (N == 0) return ptr<decltype(p1)>{&p1};
        if constexpr (N == 1) return ptr<decltype(p2)>{&p2};
    } else if constexpr (requires { T{any_type{}}; }) {
        auto&& [p1] = t;
        if constexpr (N == 0) return ptr<decltype(p1)>{&p1};
    }
}

template <auto Ptr>
[[nodiscard]] consteval auto get_name() -> std::string_view {
    return std::source_location::current().function_name();
}

template <auto N, class T>
constexpr auto get_name_impl =
    detail::get_name<detail::nth_ptr<N>(detail::external<T>)>();

struct $struct$ {
    int $field$;
};
constexpr auto $name = get_name_impl<0, detail::$struct$>;
constexpr auto $end =
    $name.substr($name.find("$field$") + sizeof("$field$") - 1);
constexpr auto $begin = $name[$name.find("$field$") - 1];
}  // namespace detail

template <auto N, class T>
constexpr auto get_name = [] {
    const auto name = detail::get_name_impl<N, T>;
    const auto begin = name.find(detail::$end);
    const auto tmp = name.substr(0, begin);
    return tmp.substr(tmp.find_last_of(detail::$begin) + 1);
}();

template <auto N>
[[nodiscard]] consteval auto nth(auto... args) {
    return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) {
        return [](decltype((void*)Ns)..., auto* nth, auto*...) {
            return *nth;
        }(&args...);
    }(std::make_index_sequence<N>{});
}

template <auto N, class T>
constexpr auto get(T&& t) {
    if constexpr (requires { T{any_type{}, any_type{}, any_type{}}; }) {
        auto&& [p1, p2, p3] = t;
        // structure bindings is not constexpr :/
        if constexpr (N == 0) return ptr<decltype(p1)>{&p1};
        if constexpr (N == 1) return ptr<decltype(p2)>{&p2};
        if constexpr (N == 2) return ptr<decltype(p3)>{&p3};
    } else if constexpr (requires { T{any_type{}, any_type{}}; }) {
        auto&& [p1, p2] = t;
        // structure bindings is not constexpr :/
        if constexpr (N == 0) return ptr<decltype(p1)>{&p1};
        if constexpr (N == 1) return ptr<decltype(p2)>{&p2};
    } else if constexpr (requires { T{any_type{}}; }) {
        auto&& [p1] = t;
        // structure bindings is not constexpr :/
        if constexpr (N == 0) return ptr<decltype(p1)>{&p1};
    }
}

template <class T, auto N>
[[nodiscard]] consteval auto member_name() {
    constexpr auto name = get_name<N, T>;
    return [&]<auto... Ns>(std::index_sequence<Ns...>) {
        return fixed_string<sizeof...(Ns)>{name[Ns]...};
    }(std::make_index_sequence<name.size()>{});
}

template <class T>
[[nodiscard]] constexpr auto to_tuple(const T& t) {
    if constexpr (requires { T{any_type{}, any_type{}, any_type{}}; }) {
        auto&& [p1, p2, p3] = t;
        return std::tuple(
            named<member_name<T, 0>(), decltype(p1)>{.value = p1},
            named<member_name<T, 1>(), decltype(p2)>{.value = p2},
            named<member_name<T, 2>(), decltype(p2)>{.value = p3});
    } else if constexpr (requires { T{any_type{}, any_type{}}; }) {
        auto&& [p1, p2] = t;
        return std::tuple(
            named<member_name<T, 0>(), decltype(p1)>{.value = p1},
            named<member_name<T, 1>(), decltype(p2)>{.value = p2});
    } else if constexpr (requires { T{any_type{}}; }) {
        auto&& [p1] = t;
        return std::tuple(
            named<member_name<T, 0>(), decltype(p1)>{.value = p1});
    } else {
        return std::tuple();
    }
}

struct foo {
    int a;
    int b;
};

constexpr auto t = to_tuple(foo{.a=42, .b=87});
static_assert("a" == std::get<0>(t).name and 42 == std::get<0>(t).value);
static_assert("b" == std::get<1>(t).name and 87 == std::get<1>(t).value);

网站公告

今日签到

点亮在社区的每一天
去签到