泛型编程

长期以来,软件重用一直都是软件工程追求的目标,而泛型编程为软件重用创造了可能性。所谓泛型编程,指的是通过组件的灵活组合来实现软件,而这些组件通过对定义做出最小“假设”来实现最大灵活性。

c++模板

在函数与类的定义 / 声明前,加上模板列表,在列表中指定在函数以及类的定义 / 声明中使用的模板参数

//class/typename定义的T/U是类型参数,size_t定义的S是非类型参数
template<size_t S, class T, typename u>
void fill_container(T& container, U v) {
    for (size_t i=0;i<S;++i) {
        container.push_back(v);
    }
}
  • 显示实例化,加快编译速度,其它编译单元直接用显示实例化的符号
     template<typename T, typename U>
     void fill_container(T& container, U v, size_t s) {
         for (size_t i=0;i<s;++i) {
             container.push_back(v);
         }
     }
     template
     void fill_container<std::vector<int>, int>(std::vector<int>&, int, size_t);
    
  • 特化 为特定参数类型提供特定实现版本,提供类似函数重载的支持
     template<size_t Size, class T, typename U>
     void fill(T& collection, U value) {
         std::cout << "Universal" << std::endl;
         for (size_t i = 0; i != Size; ++i) {
             collection.push_back(value);
         }
     }
     template <>
     void fill<10, std::vector, double>(std::vector& collection, double value) {
         std::cout << "Explicit (full) template specialization" << std::endl;
         for (size_t i = 0; i != 10; ++i) {
             collection.push_back(value + 2.0);
         }
     }
    
  • 偏特化
  • 不定参模板
     double sum() {
         return 0.0;
     }
     template <typename T, typename... Targs>
     double sum(T value, Targs... Fargs) {
         return static_cast<double>(value) + sum(Fargs...);
     }
    

问题

  1. 类型约束晦涩难懂
  2. 生成的代码急速膨胀
  3. ABI 兼容性糟糕 接口不要使用STL
  4. 错误消息很难理解

Concepts

解决问题1和4,将一组通用的约束定义为一个concept,并且,在定义模板函数与模板类中,直接使用这些concept替换通用的typenameclass

template <参数模板>
concept 名称 = 约束表达式;
class BaseClass {
public:
    int32_t getValue() const {
        return 1;
    }
};
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;
}
  • 通过约束与 concept 这两个 C++ 核心语言特性变更(高级抽象),实现了对模板参数列表与参数的约束的逻辑分离
  • 从 C++20 标准及其演进标准之后,concept 之于 C++ 泛型编程,正如 class 之于 C++ 面向对象

约束表达式

通过逻辑操作符的方式进行组合的,用于定义更复杂的 concept

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 FloatingPoint = std::is_floating_point_v<T>;
 
template <class T>
concept Number = Integral<T> || FloatingPoint<T>;

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;
}

乌托邦

xl

Stay hungry, Stay foolish.