逗号运算符(非常重要)

逗号运算符规则:

表达式1, 表达式2
// 计算表达式1(但丢弃结果)
// 返回表达式2 的值和类型

int x = (42, 100);  // x = 100(丢弃42)
decltype(42, 100)  // 推导为 int(100的类型)

也就是说,逗号运算符返回的只与最后一个表达式下相关

应用示例:在编译期检测是否还有某个方法
// SIFINAE技术:用于在编译期检测类型是否具有特定方法
template <typename F, typename... Args> class has_compute {
  private:
    template <typename U>
    // 注意增加参数是必须的,目的是为了区分重载,否则会和下面的test(...)冲突,优先级更高
    static auto test(bool) -> decltype(std::declval<U>().compute(std::declval<Args>()...), std::true_type{});

    template <typename> static std::false_type test(...);

  public:
    static constexpr bool value = decltype(test<F>(true))::value;
};
应用示例:通用的检测是否有某个方法
// SIFINAE技术:用于在编译期检测类型是否具有特定方法
#define HAS_METHOD(method_name)                                                                                        \
    template <typename T, typename... Args> class has_##method_name {                                                  \
      private:                                                                                                         \
        template <typename U>                                                                                          \
        static auto test(int) -> decltype(std::declval<U>().method_name(std::declval<Args>()...), std::true_type{});   \
                                                                                                                       \
        template <typename> static std::false_type test(...);                                                          \
                                                                                                                       \
      public:                                                                                                          \
        static constexpr bool value = decltype(test<T>(0))::value;                                                     \
    };

HAS_METHOD(compute)  // 检测是否有 compute 方法

C++20格式化字符串

总结:

  • 使用只读的std::string_view来读取字符串,提高效率
  • 使用20的格式化字符串功能:std::vformat
  • 对可变参数进行字符串格式化:std::make_format_args

需要深入理解的点:

  • 格式化的规则都有哪些,如{},其它规则都是什么?
  • 可变参数如何解析?除了递归调用,有没有其它方法
std::string msg = "123{},{}";
std::string_view fmt(msg);   //只读的字符串视图,主要是保存字符的index等信息,无法修改

template <typename... T>
void debug(std::string_view fmt,T&&... arg)
{
    const auto& msg = std::vformat(fmt, std::make_format_args(arg...));
    //c++20的格式化字符串
}

C++20 requires关键字

参考链接

可变参数的展开(##VA_ARGS)

使用##VA_ARGS来对可变参数进行扩展,展开,使用语法:

  • 定义:预处理宏
  • 作用:结合…来使用,是对它的解包
  • 说明:使用前面的##主要的原因在于,防止可变参数为空时报错

using给函数对象声明类型别名,支持函数调用异步调用场景

  • 定义:
    using FuncCb  =  std::function<void(double)> 
  • 作用:声明函数对象的类型别名,可以将函数对象参数化
  • 示例:
using FuncCb = std::function<void(double,const std::string&)>;
struct RunCb
{
    void setCb(const FuncCb cb)
    {
        _cb = cb;
    }
    FuncCb getCb()
    {
        return _cb;
    }

    FuncCb _cb;
};
void cb1(double val,const std::string& str)
{
    cout<<"cb1  "<<val<<" name:"<<str<<endl;
}

void cb2(double val,const std::string& str)
{
    cout<<"cb2  "<<val<<" name:"<<str<<endl;
}

int main()
{
    RunCb cb;
    cb.setCb(cb1);
    auto fun = cb.getCb();
    fun(21.1,"hello");
    cb.setCb(cb2);
    fun = cb.getCb();
    fun(21.1,"hello");
    return 0;
}

使用模版的模版参数

#pragma once
#include <deque>

//模板的模板参数只能用在类模板、成员函数中,无法应用于函数模板中
template<typename T,template<typename ELEM,typename ALLOC = std::allocator<ELEM>> class CONT = std::deque>
class Stack{
    public:
        void push(T const& value)
        {
            elems.push_front(value);
        }
        void pop()
        {
            elems.pop_front();
        }

        T top() const
        {
            return elems.front();
        }

        bool empty() const{
            return elems.empty();
        }

        template<typename T2,template<typename,typename> class CONT2>
        Stack<T,CONT>& operator=(Stack<T2,CONT2> const& stack)
        {
            if((void*)this == (void*)& stack)
                return *this;
            Stack<T2,CONT2> tmp(stack);
            elems.clear();
            while (!tmp.empty())
            {
                elems.push_front(tmp.top());
                tmp.pop();
            }
            return *this;
        }

    private:
        CONT<T> elems;
};

std::is_same_v的底层实现

std::is_same_v是一个类型特征(type trait)工具,用于在编译期判断两个类型是否完全相同,属于严格判断

#include <type_traits>

// 基本用法
static_assert(std::is_same_v<int, int>);        // true
static_assert(!std::is_same_v<int, float>);     // true
static_assert(!std::is_same_v<int, const int>); // true (const修饰不同)

主要的目的有以下几个点:

  • 模板元编程中的类型检查
  • SFINATE(替换失败不是错误)和概念约束
// 只允许 int 类型的函数
template<typename T>
std::enable_if_t<std::is_same_v<T, int>, void>
foo(T value) {
    std::cout << "Only accepts int\n";
}
  • 静态断言保证类型安全
  • 类型推导验证

核心实现如下(可运行版):

// 自定义实现std::is_same,使用模板元编程的方式
template <typename T, T v> struct integral_constant_cus {
    static constexpr T value = v;
    using value_type = T;
    using type = integral_constant_cus;  // using声明,方便模板元编程调用

    constexpr operator value_type() const noexcept { return value; }  // 转换为value_type类型
};

using true_type_cus = integral_constant_cus<bool, true>;
using false_type_cus = integral_constant_cus<bool, false>;

template <typename T, typename U> struct is_same_cus : false_type_cus {};  // 默认不相同
template <typename T> struct is_same_cus<T, T> : true_type_cus {};         // 特化相同

template <typename T, typename U> inline constexpr bool is_same_cus_v = is_same_cus<T, U>::value;  // 方便使用的变量模板
作者:admin  创建时间:2023-04-26 14:34
最后编辑:admin  更新时间:2025-10-10 17:51