文章目录
一、cppreference和stackoverflow解释
仅说一点:右值也可以放到等号左边
#include <iostream>
struct S
{
S() : m{42} {}
S(int a) : m{a} {}
int m;
};
int main()
{
S s;
// 表达式 `S{}` 是纯右值
// 可以出现在赋值表达式的右侧
s = S{};
std::cout << s.m << '\n';
// 表达式 `S{}` 是纯右值
// 也可以在左侧使用
std::cout << (S{} = S{7}).m << '\n';
}
二、获取变量的类型cppdemangle.h
cppdemangle.h
#pragma once
#include <typeinfo>
#include <type_traits>
#include <string>
#if (defined(__GNUC__) || defined(__clang__)) && __has_include(<cxxabi.h>)
#include <cxxabi.h>
#include <cstdlib>
#endif
namespace _cppdemangle_details {
static std::string cppdemangle(const char *name) {
#if (defined(__GNUC__) || defined(__clang__)) && __has_include(<cxxabi.h>)
int status;
char *p = abi::__cxa_demangle(name, 0, 0, &status);
std::string s = p ? p : name;
std::free(p);
#else
std::string s = name;
#endif
return s;
}
static std::string cppdemangle(std::type_info const &type) {
return cppdemangle(type.name());
}
template <class T>
static std::string cppdemangle() {
std::string s{cppdemangle(typeid(std::remove_cv_t<std::remove_reference_t<T>>))};
if (std::is_const_v<std::remove_reference_t<T>>)
s += " const";
if (std::is_volatile_v<std::remove_reference_t<T>>)
s += " volatile";
if (std::is_lvalue_reference_v<T>)
s += " &";
if (std::is_rvalue_reference_v<T>)
s += " &&";
return s;
}
}
using _cppdemangle_details::cppdemangle;
// Usage:
//
// cppdemangle<int>()
// => "int"
//
// int i;
// cppdemangle<decltype(i)>()
// => "int"
//
// int i;
// cppdemangle<decltype(std::as_const(i))>()
// => "int const &"
print.h
#include <type_traits>
#include <iostream>
#include <iomanip>
#include <string>
#include <string_view>
#include <optional>
#include <variant>
namespace _print_details {
template <class T, class = void>
struct _printer {
static void print(T const &t) {
std::cout << t;
}
using is_default_print = std::true_type;
};
template <class T, class = void>
struct _is_default_printable : std::false_type {
};
template <class T>
struct _is_default_printable<T, std::void_t<std::pair<typename _printer<T>::is_default_print, decltype(std::declval<std::ostream &>() << std::declval<T const &>())>>> : std::true_type {
};
template <class T, class = void>
struct _is_printer_printable : std::true_type {
};
template <class T>
struct _is_printer_printable<T, std::void_t<typename _printer<T>::is_default_print>> : std::false_type {
};
template <class T, class = void>
struct is_printable : std::disjunction<_is_default_printable<T>, _is_printer_printable<T>> {
};
template <class T>
using _rmcvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
template <class T, class U = void, class = void>
struct _enable_if_tuple {
using not_type = U;
};
template <class T, class U>
struct _enable_if_tuple<T, U, std::void_t<decltype(std::tuple_size<T>::value)>> {
using type = U;
};
template <class T, class U = void, class = void>
struct _enable_if_map {
using not_type = U;
};
template <class T, class U>
struct _enable_if_map<T, U, std::enable_if_t<std::is_same_v<typename T::value_type, std::pair<typename T::key_type const, typename T::mapped_type>>>> {
using type = U;
};
template <class T, class U = void, class = void>
struct _enable_if_iterable {
using not_type = U;
};
template <class T, class U>
struct _enable_if_iterable<T, U, std::void_t<typename std::iterator_traits<decltype(std::begin(std::declval<T const &>()))>::value_type>> {
using type = U;
};
template <class T, class U = void, class = void>
struct _enable_if_has_print {
using not_type = U;
};
template <class T, class U>
struct _enable_if_has_print<T, U, std::void_t<decltype(std::declval<T const &>().do_print())>> {
using type = U;
};
/* template <class T, class U> */
/* struct _enable_if_iterable<T, U, std::void_t<typename std::iterator_traits<typename T::const_iterator>::value_type>> { */
/* using type = U; */
/* }; */
template <class T>
struct _is_char : std::false_type {
};
template <>
struct _is_char<char> : std::true_type {
};
template <>
struct _is_char<wchar_t> : std::true_type {
};
template <class T, class U = void, class = void>
struct _enable_if_char {
using not_type = U;
};
template <class T, class U>
struct _enable_if_char<T, U, std::enable_if_t<_is_char<T>::value>> {
using type = U;
};
template <class T, class U = void, class = void>
struct _enable_if_string {
using not_type = U;
};
template <class T, class Alloc, class Traits, class U>
struct _enable_if_string<std::basic_string<T, Alloc, Traits>, U, typename _enable_if_char<T>::type> {
using type = U;
};
template <class T, class Traits, class U>
struct _enable_if_string<std::basic_string_view<T, Traits>, U, typename _enable_if_char<T>::type> {
using type = U;
};
template <class T, class U = void, class = void>
struct _enable_if_c_str {
using not_type = U;
};
template <class T, class U>
struct _enable_if_c_str<T, U, std::enable_if_t<std::is_pointer_v<std::decay_t<T>> && _is_char<std::remove_const_t<std::remove_pointer_t<std::decay_t<T>>>>::value>> {
using type = U;
};
template <class T, class U = void, class = void>
struct _enable_if_optional {
using not_type = U;
};
template <class T, class U>
struct _enable_if_optional<std::optional<T>, U, void> {
using type = U;
};
template <class T, class U = void, class = void>
struct _enable_if_variant {
using not_type = U;
};
template <class ...Ts, class U>
struct _enable_if_variant<std::variant<Ts...>, U, void> {
using type = U;
};
template <class T>
struct _printer<T, typename _enable_if_has_print<T>::type> {
static void print(T const &t) {
t.do_print();
}
};
template <class T>
struct _printer<T, typename _enable_if_has_print<T, typename _enable_if_iterable<T, typename _enable_if_c_str<T, typename _enable_if_string<T, typename _enable_if_map<T>::not_type>::not_type>::not_type>::type>::not_type> {
static void print(T const &t) {
std::cout << "{";
bool once = false;
for (auto const &v: t) {
if (once) {
std::cout << ", ";
} else {
once = true;
}
_printer<_rmcvref_t<decltype(v)>>::print(v);
}
std::cout << "}";
}
};
template <class T>
struct _printer<T, typename _enable_if_has_print<T, typename _enable_if_tuple<T, typename _enable_if_iterable<T>::not_type>::type>::not_type> {
template <std::size_t ...Is>
static void _unrolled_print(T const &t, std::index_sequence<Is...>) {
std::cout << "{";
((_printer<_rmcvref_t<std::tuple_element_t<Is, T>>>::print(std::get<Is>(t)), std::cout << ", "), ...);
if constexpr (sizeof...(Is) != 0) _printer<_rmcvref_t<std::tuple_element_t<sizeof...(Is), T>>>::print(std::get<sizeof...(Is)>(t));
std::cout << "}";
}
static void print(T const &t) {
_unrolled_print(t, std::make_index_sequence<std::max(static_cast<std::size_t>(1), std::tuple_size_v<T>) - 1>{});
}
};
template <class T>
struct _printer<T, typename _enable_if_has_print<T, typename _enable_if_map<T>::type>::not_type> {
static void print(T const &t) {
std::cout << "{";
bool once = false;
for (auto const &[k, v]: t) {
if (once) {
std::cout << ", ";
} else {
once = true;
}
_printer<_rmcvref_t<decltype(k)>>::print(k);
std::cout << ": ";
_printer<_rmcvref_t<decltype(v)>>::print(v);
}
std::cout << "}";
}
};
template <class T>
struct _printer<T, typename _enable_if_has_print<T, typename _enable_if_string<T>::type>::not_type> {
static void print(T const &t) {
std::cout << std::quoted(t);
}
};
template <class T>
struct _printer<T, typename _enable_if_c_str<T>::type> {
static void print(T const &t) {
std::cout << t;
}
};
template <class T>
struct _printer<T, typename _enable_if_char<T>::type> {
static void print(T const &t) {
T s[2] = {t, T('\0')};
std::cout << std::quoted(s, T('\''));
}
};
template <>
struct _printer<std::nullptr_t, void> {
static void print(std::nullptr_t const &) {
std::cout << "nullptr";
}
};
template <>
struct _printer<std::nullopt_t, void> {
static void print(std::nullopt_t const &) {
std::cout << "nullopt";
}
};
template <>
struct _printer<std::monostate, void> {
static void print(std::monostate const &) {
std::cout << "monostate";
}
};
template <class T>
struct _printer<T, typename _enable_if_has_print<T, typename _enable_if_optional<T>::type>::not_type> {
static void print(T const &t) {
if (t.has_value()) {
_printer<typename T::value_type>::print(*t);
} else {
_printer<std::nullopt_t>::print(std::nullopt);
}
}
};
template <class T>
struct _printer<T, typename _enable_if_has_print<T, typename _enable_if_variant<T>::type>::not_type> {
static void print(T const &t) {
std::visit([] (auto const &v) {
_printer<_rmcvref_t<decltype(v)>>::print(v);
}, t);
}
};
template <>
struct _printer<bool, void> {
static void print(bool const &t) {
if (t) {
std::cout << "true";
} else {
std::cout << "false";
}
}
};
template <class T0, class ...Ts>
void print(T0 const &t0, Ts const &...ts) {
_printer<_rmcvref_t<T0>>::print(t0);
((std::cout << " ", _printer<_rmcvref_t<Ts>>::print(ts)), ...);
std::cout << "\n";
}
template <class T0, class ...Ts>
void printnl(T0 const &t0, Ts const &...ts) {
_printer<_rmcvref_t<T0>>::print(t0);
((std::cout << " ", _printer<_rmcvref_t<Ts>>::print(ts)), ...);
}
template <class T, class = void>
class print_adaptor {
T const &t;
public:
explicit constexpr print_adaptor(T const &t_) : t(t_) {
}
friend std::ostream &operator<<(std::ostream &os, print_adaptor const &&self) {
auto oldflags = os.flags();
os << "[object 0x" << std::hex << reinterpret_cast<uintptr_t>(
reinterpret_cast<void const volatile *>(std::addressof(self.t))) << ']';
os.flags(oldflags);
return os;
}
};
template <class T>
class print_adaptor<T, std::enable_if_t<is_printable<T>::value>> {
T const &t;
public:
explicit constexpr print_adaptor(T const &t_) : t(t_) {
}
friend std::ostream &operator<<(std::ostream &os, print_adaptor const &&self) {
printnl(self.t);
return os;
}
};
template <class T>
explicit print_adaptor(T const &) -> print_adaptor<T>;
}
using _print_details::print;
using _print_details::printnl;
using _print_details::print_adaptor;
using _print_details::is_printable;
// Usage:
//
// map<string, optional<int>> m = {{"hello", 42}, {"world", nullopt}};
// print(m); // {"hello": 42, "world": nullopt}
/* // use of the macro below requires #include "ppforeach.h" */
/* #define DEF_PRINT(Class, TmplArgs, ...) \ */
/* template <TmplArgs> \ */
/* struct ::constl::_print_details::_printer<Class, void> { \ */
/* static void print(Class const &_cls) { \ */
/* std::cout << "{"; \ */
/* PP_FOREACH(_PRINTER_PER_MEMBER, std::cout << ", ";, __VA_ARGS__); \ */
/* std::cout << "}"; \ */
/* } \ */
/* }; */
/* #define _PRINTER_PER_MEMBER(memb) \ */
/* std::cout << #memb << ": "; \ */
/* ::constl::_print_details::_printer<_print_details::_rmcvref_t<decltype(_cls.memb)>>::print(_cls.memb); */
/* */
/* #define PRINT(x) print(#x " :=", x) */
1、decaltype直接取变量和取变量表达式的区别
decaltype变量,直接取得是变量的类型,和表达式的类型是不一样的。
- 前者取的是变量的类型
- 后者取得是表达式的类型,decaltype变量,直接取得是变量的类型,和表达式的区别。表达式是可以赋值的呀
取变量的类型:
使用gun++17编译
int main()
{
int a = 1;
std::cout<<_cppdemangle_details::cppdemangle<decltype(a)>()<<std::endl;
}
测试:
Program returned: 0
Program stdout
int
取表达式的类型:
int main()
{
int a = 1;
std::cout<<cppdemangle<decltype((a))>()<<std::endl;
}
测试:
Program returned: 0
Program stdout
int &
2.void func(int a)和void func(int&& a)无法构成重载
函数的形参类型int&&和int会冲突,入参无法区分prvalue和xvalue。也就是说纯右值的参数可以用&&这样的函数参数类型去接上述两种类型的参数
/*
void func(int a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
*/
void func(int&& a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
void func(int const& a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
int main()
{
int a = 1;
std::cout<<cppdemangle<decltype(1)>()<<std::endl;//prvalue
std::cout<<cppdemangle<decltype(std::move(a))>()<<std::endl;//xvalue
std::cout<<cppdemangle<decltype((a))>()<<std::endl;//lvalue
func(1);//prvalue
func(std::move(a));//xvalue
func(a);//lvalue
}
测试
Program returned: 0
Program stdout
int
int &&
int &
void func(int&&)
void func(int&&)
void func(const int&)
3.区分this指针式左值还是右值的方法
#include <iostream>
#include <string>
#include <typeinfo>
#include <type_traits>
#include <string>
#if (defined(__GNUC__) || defined(__clang__)) && __has_include(<cxxabi.h>)
#include <cxxabi.h>
#include <cstdlib>
#endif
namespace _cppdemangle_details {
static std::string cppdemangle(const char *name) {
#if (defined(__GNUC__) || defined(__clang__)) && __has_include(<cxxabi.h>)
int status;
char *p = abi::__cxa_demangle(name, 0, 0, &status);
std::string s = p ? p : name;
std::free(p);
#else
std::string s = name;
#endif
return s;
}
static std::string cppdemangle(std::type_info const &type) {
return cppdemangle(type.name());
}
template <class T>
static std::string cppdemangle() {
std::string s{cppdemangle(typeid(std::remove_cv_t<std::remove_reference_t<T>>))};
if (std::is_const_v<std::remove_reference_t<T>>)
s += " const";
if (std::is_volatile_v<std::remove_reference_t<T>>)
s += " volatile";
if (std::is_lvalue_reference_v<T>)
s += " &";
if (std::is_rvalue_reference_v<T>)
s += " &&";
return s;
}
}
using _cppdemangle_details::cppdemangle;
struct S{
int a;
int b;
int getA() const& {
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return a;
}
int getA() &{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return a;
}
int getA() &&{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return a;
}
int getA() const &&{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return a;
}
};
int main()
{
S().getA();
S s;
s.getA();
const S cs{};
cs.getA();
std::move(cs).getA();
}
测试:
Program returned: 0
Program stdout
int S::getA() &&
int S::getA() &
int S::getA() const &
int S::getA() const &&
4.区分this指针左值,右值重载的应用例子
如果不定义右值的this指针的相关函数,给func传入的是右值,最后接的func也是左值参数类型的func
void func(int&& a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
void func(int const& a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
struct S{
int a;
int b;
int const& getA() const {
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return a;
}
int& getA() {
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return a;
}
};
int main()
{
func(S().getA());
}
测试:
Program returned: 0
Program stdout
int& S::getA()
void func(const int&)
解决办法1:使用move
int main()
{
func(std::move(S{}.getA()));
}
解决办法2:重载this指针左值和右值的相关成员函数
入参是一个右值,使用能接收右值的func
void func(int&& a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
void func(int const& a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
struct S{
int a;
int b;
int const& getA() const& {
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return a;
}
int& getA() &{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return a;
}
int&& getA() &&{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return std::move(a);
}
int const&& getA() const &&{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return std::move(a);
}
};
int main()
{
func(S().getA());
}
测试:
Program returned: 0
Program stdout
int&& S::getA() &&
void func(int&&)