C++26绑定作为条件
struct foo {
int a{};
int b{};
constexpr operator bool() const { return a != b; }
};
auto test = [](auto... ts) {
if (auto [a, b] = foo{ts...}) {
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 [:
std::meta::substitute(^type_list,
std::array{^int, ^float, ^short}
| std::views::reverse
| 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);
addressof(int{});
}
span.at
std::array<int, 42> storage{};
const auto span = std::span(storage);
(void)span.at(0);
(void)span.at(storage.size());
无异与有异常不同
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);
缓存对齐数组
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;
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();
std::cout << std::string(sp.data(),sp.size());
}
块流实现连接串
[[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;
}
}
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];
}
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;
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 <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);