Concept

博客围绕C++展开,介绍了原子约束,它由表达式E与参数映射组成,编译器实例化时会检查参数是否满足约束。还提到requires与普通约束表达式不同,完成参数替换后语法和约束检查全通过才返回true。此外,说明了requires子句用于判断所约束声明在‘上下文’中是否可行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <concepts>
#include <iostream>

class BaseClass {
public:
    int getValue() const {
        return 1;
    }
};

class DerivedClass: public BaseClass {
public:
    int getValue() const {
        return 2;
    }
};

class NonDerivedClass {
public:
    int getValue() const {
        return 3;
    }
};

template<class T>
concept DerivedOfBaseClass = std::is_base_of_v<BaseClass, T>;

template <DerivedOfBaseClass T>
void doGetValue(const T& a) {
    std::cout << "Get value:" << a.getValue() << std::endl;
}

int c2() {
    DerivedClass d;
    doGetValue(d);

    BaseClass b;
    doGetValue(b);

    // 解除注释会引发错误
    // NonDerivedClass n;
    // doGetValue(n);

    return 0;
}

int main() {
    c2();

    return 0;
}

template<typename T>
constexpr bool get_value() { return T::value; }
 
template<typename T>
    requires (sizeof(T) > 1 && get_value<T>())
void f(T) {
    std::cout << "template version" << std::endl;
}

void f(int32_t) {
    std::cout << "int version" << std::endl;
}

void c15() {
    f('A');
} 

 &&:


template<class T>
concept Integral = std::is_integral_v<T>;
 
template<class T>
concept SignedIntegral = Integral<T> && std::is_signed_v<T>;
 
template<class T>
concept UnsignedIntegral = Integral<T> && !SignedIntegral<T>;

||:


template <class T>
concept Integral = std::is_integral_v<T>;
 
template <class T>
concept FloatingPoint = std::is_floating_point_v<T>;
 
template <class T>
concept Number = Integral<T> || FloatingPoint<T>;

原子约束:


template <class T>
concept Floating = std::is_floating_point_v<T>;

template <class T>
concept BadNumber = std::is_floating_point_v<T> && std::is_floating_point_v<T>;

template <class T>
concept Number = Floating<T> && std::is_floating_point_v<T>;

template <Floating T> // #1
void func(T) {}

template <BadNumber T> // #2
void func(T) {}

template <Number T> // #3
void func(T) {}

原子约束,由表达式 E 与 E 的参数映射组成。参数映射指的是 E 中受约束实体的模板参数(template parameter)与实例化时使用的模板实参(template argument)之间的映射关系。

E 的值必须是 bool 类型,不允许通过任何隐式转换变为 bool 型。

编译器在实例化过程中,会检查参数是否满足原子约束。编译器会根据参数映射关系,将模板实参替换成表达式 E 中的形参。

如果替换后的表达式是一个非法类型或者非法表达式,说明当前实例化参数不满足约束

requires 与普通约束表达式不同,如果其定义体在完成参数替换后,存在非法的类型或表达式,或者 requires 定义中的约束存在冲突时,会返回 false。反之,如果完成参数替换后语法检查以及约束检查全部成功之后,才会返回 true。


template<typename T>
concept Histogram = requires(T h1, T h2) {
    h1.getMoments();         // 要求有getMoments接口
    T::count;                // 要求有静态变量count
    h1.moments;              // 要求有成员变量moments
    h1 + h2;                 // 要求对象能够进行+操作

    typename T::type;        // 要求存在类型成员type
    typename std::vector<T>; // 要求能够模板实例化并与std::vector组合使用
    
    { h1.getSubHistogram() } -> same_as<T>;    // 要求接口返回类型与T一致
    { h1.getUnit() } -> convertible_to<float>; // 要求接口返回类型能转换成float,本质上接口返回类型可能是double
    { h1 = std::move(h2) } noexcept;          // 要求表达式不能抛出异常
    
    requires sizeof(T) > 4;
};

requires子句:

requires 子句存在的意义是判断它所约束的声明在“上下文”中是否可行


export template <typename T1, typename  T2>
    requires requires (T1 x, T2 y) { x + y; }
std::common_type<T1, T2> func(
    T1 arg1, T2 arg2
) {
    return arg1 + arg2;
}

### C++ 中的 `concept` 特性介绍和使用方法 C++20 引入了 `concept` 特性,为模板编程带来了更强的类型约束和更清晰的错误信息支持。这一特性通过在编译时对模板参数进行限制,使得开发者可以定义更加明确、可读性更高的泛型代码。 #### 概念的基本定义 `concept` 允许开发者定义一个逻辑条件集合,这些条件描述了模板参数需要满足的要求。例如,可以定义一个名为 `Integral` 的概念来限定模板参数必须是整数类型: ```cpp template<typename T> concept Integral = std::is_integral_v<T>; ``` 这种写法比传统的 `std::enable_if` 更加直观,并且能够显著提高代码的可读性和维护性[^3]。 #### 使用 `concept` 优化模板函数 通过 `concept`,可以简化模板函数的定义,使其意图更加明确。例如,定义一个用于判断两个值是否相等的函数模板,要求传入的类型必须是整数类型: ```cpp template<Integral T> bool equal(const T& a, const T& b) { return a == b; } ``` 与使用 `std::enable_if` 的传统方式相比,这种方式不仅语法更为简洁,而且在编译时如果传递了不满足条件的类型,错误信息也会更加友好[^2]。 #### 结合范围库使用 `concept` `concept` 还可以与 C++20 的范围(Ranges)库结合使用,以确保传入的参数是一个范围。这可以通过指定 `std::ranges::range` 类型约束来实现: ```cpp #include <vector> #include <ranges> #include <iostream> void print3(const std::ranges::range auto& c) { for (auto&& elem : c) { std::cout << elem << ", "; } std::cout << std::endl; } int main() { std::vector<int> c{1, 2, 4, 5, 12, 23, 88, 23, 17}; print3(c); } ``` 上述代码中的 `print3` 函数接受任何符合 `std::ranges::range` 约束的对象作为参数,并对其进行遍历输出操作。这种方法不仅提高了代码的通用性,还增强了代码的安全性和可读性[^1]。 #### 总结 `concept` 是 C++20 中非常重要的新特性之一,它解决了模板编程中长期存在的问题——如何有效地对模板参数施加约束。通过引入 `concept`,不仅可以编写出更加清晰、安全的泛型代码,还可以获得更友好的编译错误提示,从而极大地提升了开发效率和代码质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值