C++模板元编程:编译时的魔法
1. 引言
在C++的世界中,模板元编程是一种在编译时执行计算的强大技术。它允许开发者编写高度灵活和高效的代码,这些代码可以在不牺牲性能的前提下,根据类型和值的不同而变化。本文将深入探讨模板元编程的奥秘,并展示如何在现代C++开发中利用这一技术。
2. C++模板基础
C++模板是泛型编程的基石,它们提供了一种编写与数据类型无关的代码的方法。在这一节中,我们将深入探索模板的基本概念、使用方式以及它们在C++中的多种应用。
2.1 模板的定义和使用
模板允许我们定义可以处理多种数据类型的函数或类。下面是一个简单的函数模板示例,它演示了如何打印任意类型的数据:
#include <iostream>
#include <string>template <typename T>
void printValue(T value) {std::cout << value << std::endl;
}int main() {printValue(10); // 打印整数printValue(3.14); // 打印浮点数printValue("Hello"); // 打印字符串return 0;
}
2.2 函数模板和类模板的区别
函数模板定义了操作数据的函数,而类模板定义了可以包含数据和行为的类型。以下是类模板的一个示例:
template <typename T>
class Stack {
private:T* elements;size_t size;size_t capacity;public:Stack(size_t initialCapacity);~Stack();void push(const T& element);T pop();size_t getSize() const;
};
这个Stack
类模板可以用于创建任何类型的栈。
2.3 模板参数和模板特化
模板参数允许我们定义通用的代码,而模板特化则允许我们为特定的类型提供特定的实现。以下是模板特化的一个例子:
// 通用的print函数模板
template <typename T>
void print(T value) {std::cout << value << std::endl;
}// 特化版本,用于打印字符串
template <>
void print(const std::string& value) {std::cout << "'" << value << "'" << std::endl;
}int main() {print(123); // 使用通用版本print("test"); // 使用特化版本return 0;
}
2.4 模板参数的默认值
我们可以为模板参数提供默认值,这样在调用模板时可以省略某些参数:
template <typename T, typename Allocator = std::allocator<T>>
class Vector {// ...
};
在这个例子中,如果用户没有指定分配器类型,Vector
类模板将默认使用std::allocator
。
2.5 非类型模板参数
除了类型参数外,模板还可以接受非类型参数,如整数:
template <int size>
class FixedSizeArray {T (&data)[size];
public:FixedSizeArray(T* array) {for (int i = 0; i < size; ++i) {data[i] = array[i];}}
};
这个FixedSizeArray
类模板创建了一个固定大小的数组的引用。
2.6 模板的友元声明
模板可以声明友元函数或类,这些友元可以访问模板的私有成员:
template <typename T>
class MyClass {
private:T privateData;public:template <typename U>friend class MyOtherClass;
};template <typename T>
class MyOtherClass {
public:void accessPrivateData(MyClass<T>& obj) {// 可以访问obj.privateData}
};
2.7 模板与继承
模板可以与继承一起使用,创建灵活的类型层次结构:
template <typename T>
class Base {virtual void doSomething() = 0;
};template <typename T>
class Derived : public Base<T> {void doSomething() override {// 实现细节}
};
在这个例子中,Derived
类模板继承自Base
类模板,并提供了doSomething
的实现。
3. 模板元编程的基本原理
模板元编程是C++中一种高级技术,它允许开发者在编译时进行类型检查和计算。这种技术可以极大地提高程序的性能和灵活性。在本节中,我们将深入探讨模板元编程的基本原理,并提供丰富的示例来展示其应用。
3.1 编译时计算
模板元编程的核心是编译时计算。这意味着所有与类型相关的逻辑和决策都在编译阶段完成,从而避免了运行时的开销。以下是一个简单的示例,展示如何在编译时计算两个类型的平均大小:
template <typename T1, typename T2>
struct AverageSize {static const std::size_t value = (sizeof(T1) + sizeof(T2)) / 2;
};int main() {std::cout << AverageSize<int, double>::value << std::endl;// 输出 int 和 double 平均大小的字节数return 0;
}
3.2 模板元编程与运行时计算的区别
模板元编程与运行时计算的主要区别在于执行时机和性能。运行时计算在程序执行时进行,而模板元编程在编译时完成。这使得模板元编程可以提供更高的性能,因为它避免了运行时的类型检查和决策。
3.3 元组和变参模板的使用
元组和变参模板是模板元编程中两个重要的概念。元组允许我们以类型安全的方式存储和操作一系列不同类型的数据,而变参模板则允许我们编写接受任意数量参数的模板。
3.3.1 元组的使用
C++17引入了std::tuple
,它是一个可以存储不同类型的固定大小序列。以下是一个使用元组的示例:
#include <tuple>template <typename... Types>
std::tuple<Types...> make_tuple(Types... args) {return std::make_tuple(args...);
}int main() {auto myTuple = make_tuple(1, 'a', 3.14);// myTuple 是一个包含 int, char 和 double 的 tuplereturn 0;
}
3.3.2 变参模板的使用
变参模板允许我们定义接受任意数量参数的模板。以下是一个变长参数求和的示例:
template <typename T>
T sum(T t) {return t;
}template <typename T, typename... Types>
T sum(T first, Types... rest) {return first + sum(rest...);
}int main() {std::cout << sum(1, 2, 3, 4) << std::endl;// 输出 10return 0;
}
3.4 递归模板模式
递归模板模式是模板元编程中的一个强大工具,它允许我们通过递归的方式进行类型和值的操作。以下是一个使用递归模板模式实现的阶乘计算:
template <int N>
struct Factorial {static const int value = N * Factorial<N - 1>::value;
};template <>
struct Factorial<0> {static const int value = 1;
};int main() {std::cout << Factorial<5>::value << std::endl;// 输出 120return 0;
}
3.5 模板元编程中的类型特性
类型特性(Type Traits)是模板元编程中用于类型属性查询的一种技术。例如,我们可以检查一个类型是否是指针类型:
template <typename T>
struct is_pointer : std::false_type {};template <typename T>
struct is_pointer<T*> : std::true_type {};int main() {std::cout << is_pointer<int>::value << std::endl; // 输出 0std::cout << is_pointer<int*>::value << std::endl; // 输出 1return 0;
}
3.6 模板元编程的限制
尽管模板元编程非常强大,但它也有一些限制,比如编译时间的增加和模板深度限制。以下是一个示例,展示如何处理模板深度限制:
template <typename T, T v>
struct integral_constant {static const T value = v;typedef T value_type;typedef integral_constant<T, v> type;
};typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;// 使用递归展开减少模板深度
template <bool...> struct bool_pack;template <bool... values>
struct all_true : true_type {};template <bool first, bool... rest>
struct all_true<first, rest...>: integral_constant<bool, first && all_true<rest...>::value> {};int main() {std::cout << all_true<true, true, true>::value << std::endl; // 输出 1std::cout << all_true<true, false, true>::value << std::endl; // 输出 0return 0;
}
4. 深入模板元编程
模板元编程不仅仅是在编译时进行计算,它还涉及到一系列高级技术,这些技术可以让我们编写出更加强大和灵活的代码。本节将深入探讨一些高级的模板元编程技巧,并提供丰富的示例来展示它们的应用。
4.1 高级模板技巧
4.1.1 SFINAE(Substitution Failure Is Not An Error)
SFINAE是一个强大的模板编程技术,它允许我们根据类型的特性来启用或禁用某些模板实例化。以下是一个使用SFINAE的示例:
#include <type_traits>template <typename T>
using add_const_t = typename std::add_const<T>::type;template <typename T>
auto func(T& t) -> add_const_t<decltype(t++)> {return t++;
}int main() {int i = 0;static_assert(std::is_same<decltype(func(i)), int&>::value, "Should be int&");return 0;
}
4.1.2 模板特化和偏特化
模板特化和偏特化允许我们为特定的类型或类型组合提供定制化的实现:
template <typename T1, typename T2>
struct Pair { /* ... */ };template <typename T>
struct Pair<T, T> {// 为相同类型的Pair提供特化实现
};template <typename T1>
struct Pair<T1, int> {// 为第二个类型为int的Pair提供偏特化实现
};
4.2 模板递归和模板展开
4.2.1 模板递归
模板递归是一种在模板定义中使用自身的方式,它可以用于实现递归算法:
template <int N>
struct Factorial {static constexpr int value = N * Factorial<N - 1>::value;
};template <>
struct Factorial<0> {static constexpr int value = 1;
};
4.2.2 模板展开
模板展开允许我们在编译时展开模板实例,这可以用于优化性能:
template <int... Ints>
struct IntSequence {};template <int N, int... Ints>
struct MakeIntSequence {using type = typename MakeIntSequence<N - 1, N - 1, Ints...>::type;
};template <int... Ints>
struct MakeIntSequence<0, Ints...> {using type = IntSequence<Ints...>;
};template <int N>
using MakeIntSequence_t = typename MakeIntSequence<N>::type;
4.3 模板元编程在算法实现中的应用
4.3.1 编译时排序
使用模板元编程,我们可以在编译时对数据进行排序,从而避免运行时的开销:
template <int... Ints>
struct SortedInts;template <int First, int Second, int... Rest>
struct SortedInts<First, Second, Rest...> {using type = typename std::conditional<First < Second,typename SortedInts<First, Rest...>::type,typename SortedInts<Second, First, Rest...>::type>::type;
};template <int Int>
struct SortedInts<Int> {using type = IntSequence<Int>;
};
4.3.2 编译时查找
模板元编程也可以用于在编译时执行查找操作:
template <int N, int... Ints>
struct FindIndex;template <int N, int Head, int... Tail>
struct FindIndex<N, N, Head, Tail...> {static const int value = 1;
};template <int N, int Head, int... Tail>
struct FindIndex<N, Head, Tail...> {static const int value = 1 + FindIndex<N, Tail...>::value;
};template <int N>
struct FindIndex<N> {static const int value = -1;
};
4.4 模板元编程的高级应用
4.4.1 元组算法
使用模板元编程,我们可以对元组中的元素执行算法,如应用函数或变换:
template <typename F, typename Tuple, std::size_t... Is>
void apply_impl(F&& f, Tuple&& t, std::index_sequence<Is...>) {using swallow = int[];(void)swallow{0, (void(f(std::get<Is>(std::forward<Tuple>(t)))), 0)...};
}template <typename F, typename Tuple>
void apply(F&& f, Tuple&& t) {apply_impl(std::forward<F>(f), std::forward<Tuple>(t),std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}
4.4.2 表达式模板
表达式模板是一种使用模板元编程来延迟计算的技术,它常用于库设计中以提高性能:
template <typename T>
class Vector {// ...
public:template <typename U>Vector(const Vector<U>& other) {// ...}Vector operator+(const Vector& other) const {return Vector(*this).add(other);}private:Vector& add(const Vector& other) {// 实现向量加法return *this;}
};
5. 模板元编程的实用技巧
在深入探索模板元编程之后,我们需要了解一些实用的技巧来提高我们的编程实践。这些技巧将帮助我们编写更清晰、更高效且易于维护的模板代码。
5.1 编写可读性强的模板代码
5.1.1 清晰的模板参数命名
使用描述性的模板参数名称,以提高代码的可读性。
template <typename ElementType, typename AllocatorType>
class MyVector {// ...
};
5.1.2 使用类型别名
类型别名可以简化复杂的类型表达。
template <typename T>
using Ptr = std::shared_ptr<T>;Ptr<SomeClass> myPtr = std::make_shared<SomeClass>();
5.2 调试模板元编程代码的策略
5.2.1 编译器警告和错误
学会阅读和理解编译器的警告和错误信息。
5.2.2 简化模板
将复杂的模板分解为更小的部分,逐一进行测试。
5.2.3 使用static_assert
static_assert
可以在编译时检查条件,帮助调试。
template <typename T>
class MyClass {static_assert(std::is_integral<T>::value, "T must be an integral type");// ...
};
5.3 性能优化和陷阱
5.3.1 避免模板膨胀
过度使用模板可能导致模板膨胀,增加编译时间和二进制大小。
5.3.2 内联模板函数
使用inline
关键字或模板内联变量来减少函数调用开销。
template <typename T>
inline T addOne(T value) {return value + 1;
}
5.3.3 模板实例化
明智地选择模板实例化,避免不必要的实例化。
5.4 利用constexpr进行编译时计算
5.4.1 constexpr函数
使用constexpr
函数进行编译时计算。
template <typename T>
constexpr T pi = T(3.14159265358979323846);template <typename T>
constexpr T calculateCircleArea(T radius) {return pi<T> * radius * radius;
}
5.5 模板元编程与C++标准库
5.5.1 使用标准库中的Type Traits
利用<type_traits>
中的类型特性来编写更灵活的模板代码。
template <typename T>
using MaybeConst = typename std::conditional<std::is_const<T>::value, const T, T
>::type;
5.5.2 利用标准库中的元组
使用<tuple>
和<utility>
中的元组来处理多种类型的数据。
#include <tuple>template <typename... Args>
std::tuple<Args...> make_tuple_impl(Args&&... args) {return std::make_tuple(std::forward<Args>(args)...);
}template <typename... Args>
auto make_tuple(Args&&... args) {return make_tuple_impl(std::forward<Args>(args)...);
}
5.6 高级模板技术
5.6.1 模板模板参数
使用模板模板参数来参数化模板的模板。
template <template <typename> class TT>
class Wrapper {
public:template <typename T>TT<T> wrapped;
};
5.6.2 变长模板参数的递归展开
使用递归展开技术来处理变长模板参数。
template <typename... Args>
void processArgs(Args... args) {(..., processArg(std::forward<Args>(args)));
}template <typename Arg>
void processArg(Arg&& arg) {// Process single argument
}
5.7 模板元编程的最佳实践
5.7.1 保持模板的简洁性
避免在模板中使用复杂的逻辑,以减少编译时间和潜在的错误。
5.7.2 利用编译时断言
使用static_assert
来确保模板的使用符合预期。
5.7.3 编写模板友好的代码
确保你的代码可以很好地与其他模板代码协同工作。
相关文章:
C++模板元编程:编译时的魔法
1. 引言 在C的世界中,模板元编程是一种在编译时执行计算的强大技术。它允许开发者编写高度灵活和高效的代码,这些代码可以在不牺牲性能的前提下,根据类型和值的不同而变化。本文将深入探讨模板元编程的奥秘,并展示如何在现代C开发…...
SQL进阶day10————多表查询
目录 1嵌套子查询 1.1月均完成试卷数不小于3的用户爱作答的类别 1.2月均完成试卷数不小于3的用户爱作答的类别 编辑1.3 作答试卷得分大于过80的人的用户等级分布 2合并查询 2.1每个题目和每份试卷被作答的人数和次数 2.2分别满足两个活动的人 3连接查询 3.1满足条件…...
debug调试_以Pycharm为例
文章目录 作用步骤打断点调试调试窗口 作用 主要是检查逻辑错误,而非语法错误。 步骤 打断点 在需要调试的代码行前打断点,执行后会停顿在断点位置(不运行) 调试 右键“debug”,或者直接点击右上角的小虫子 调试…...
wms第三方海外仓系统:如何为中小型海外仓注入新活力
对于中小型海外仓来说,想在大型集团海外仓同台竞争中获得优胜,提升其管理效率是非常关键的一环。 我们所熟知的wms系统,也就是第三方成熟海外仓系统,正是这些海外仓企业提升管理水平、降低成本的重要工具。 1、wms第三方海外仓系…...
html是什么?http是什么?
html Html是什么?http是什么? Html 超文本标记语言;负责网页的架构; http((HyperText Transfer Protocol)超文本传输协议; https(全称:Hypertext Transfer Protocol …...
L1-007 念数字js实现
异步解法 const readline require("readline"); const rl readline.createInterface({input: process.stdin,output: process.stdout, }); const input_arr [];//储存数据 rl.on(line, function (line) {input_arr.push(line); } ); rl.on(close, function () {/…...
Perl 运算符
Perl 运算符 Perl 是一种功能强大的编程语言,广泛应用于系统管理、网络编程、GUI 创建、数据库访问等众多领域。Perl 的语法灵活,支持多种编程范式,包括过程式、面向对象和函数式编程。在 Perl 中,运算符扮演着重要的角色&#x…...
语法04 C++ 标准输入语句
标准输入 使用格式:cin >> 输入的意思就是把一个值放到变量里面去,也就是变量的赋值,这个值是由我们自己输入的。 (注意:输入变量前要先定义,输入完之后要按Enter键。) 输入多个变量,与输出类似,…...
python数据分析--- ch6-7 python容器类型的数据及字符串
python数据分析---ch6-7 python容器类型的数据及字符串 1. Ch6--容器类型的数据1.1 序列1.1.1 序列的索引操作1.1.2 加和乘操作1.1.3 切片操作1.1.4 成员测试 1.2 列表1.2.1 创建列表1.2.2 追加元素1.2.3 插入元素1.2.4 替换元素1.2.5 删除元素1.2.6 列表排序(1&…...
【Linux取经路】守护进程
文章目录 一、前台进程和后台进程二、Linux 的进程间关系三、setsid——将当前进程设置为守护进程四、daemon——设置为守护进程五、结语 一、前台进程和后台进程 Linux 中每一次用户登录都是一个 session,一个 session 中只能有一个前台进程在运行,键盘…...
Nginx之文件下载服务器
1.概述 在对外分享文件时,利用Nginx搭建一个简单的下 载文件管理服务器,文件分享就会变得非常方便。利 用Nginx的诸多内置指令可实现自动生成下载文件列表 页、限制下载带宽等功能。配置样例如下: server {listen 8080;server_name localhos…...
OpenCV学习(4.11) OpenCV中的图像转换
1. 目标 在本节中,我们将学习 使用OpenCV查找图像的傅立叶变换利用Numpy中可用的FFT功能傅立叶变换的一些应用我们将看到以下函数:**cv.dft()** ,**cv.idft()** 等 理论 傅立叶变换用于分析各种滤波器的频率特性。对于图像,使用…...
2024.6.13每日一题
LeetCode 子序列最大优雅度 题目链接:2813. 子序列最大优雅度 - 力扣(LeetCode) 题目描述 给你一个长度为 n 的二维整数数组 items 和一个整数 k 。 items[i] [profiti, categoryi],其中 profiti 和 categoryi 分别表示第 i…...
Linux命令详解(2)
文本处理是Linux命令行的重要应用之一。通过一系列强大的命令,用户可以轻松地对文本文件进行编辑、查询和转换。 cat: 这个命令用于查看文件内容。它可以一次性显示整个文件,或者分页显示。此外,cat 还可以用于合并多个文件的内容…...
iOS ReactiveCocoa MVVM
学习了在MVVM中如何使用RactiveCocoa,简单的写上一个demo。重点在于如何在MVVM各层之间使用RAC的信号来更方便的在各个层之间进行响应式数据交互。 demo需求:一个登录界面(登录界面只有账号和密码都有输入,登录按钮才可以点击操作)࿰…...
图文解析ASN.1中BER编码:结构类型、编码方法、编码实例
本文将详细介绍ASN.1中的BER编码规则,包括其编码机制、数据类型表示、以及如何将复杂的数据结构转换为二进制数据。通过本文的阅读,读者将对ASN.1中的BER编码有一个全面的理解。 目录 一.引言 二.BER编码基本结构 ▐ 1. 类型域(Type&#…...
jQuery如何停止动画队列
在jQuery中,你可以使用.stop()方法来停止动画队列。.stop()方法有几个可选的参数,可以用来控制停止动画的方式。 以下是.stop()方法的基本用法和一些参数选项: 无参数:立即停止当前动画,并跳到最后的状态。后续的动画…...
vue3+electron搭建桌面软件
vue3electron开发桌面软件 最近有个小项目, 客户希望像打开 网易云音乐 那么简单的运行起来系统. 前端用 Vue 会比较快一些, 因此决定使用 electron 结合 Vue3 的方式来完成该项目. 然而, 在实施过程中发现没有完整的博客能够记录从创建到打包的流程, 摸索一番之后, 随即梳理…...
oracle常用经典SQL查询
oracle常用经典SQL查询(转贴) oracle常用经典SQL查询 常用SQL查询: 1、查看表空间的名称及大小 select t.tablespace_name, round(sum(bytes/(1024*1024)),0) ts_size from dba_tablespaces t, dba_data_files d where t.tablespace_name d.tablespace_name grou…...
Android shell 常用 debug 命令
目录 1、查看版本2、am 命令3、pm 命令4、dumpsys 命令5、sed命令6、log定位查看APK进程号7、log定位使用场景 1、查看版本 1.1、Android串口终端执行 getprop ro.build.version.release #获取Android版本 uname -a #查看linux内核版本信息 uname -r #单独查看内核版本 1.2、…...
Unity3D Shader数据传递语法详解
在Unity3D中,Shader是用于渲染图形的一种程序,它定义了物体在屏幕上的外观。Shader通过接收输入数据(如顶点位置、纹理坐标、光照信息等)并计算像素颜色来工作。为了使得Shader能够正确运行并产生期望的视觉效果,我们需…...
计算机组成原理(五)
一、链式查询方式 接口的优先级固定不变 在链式查询的情况下,设备的优先级通常与其在链中的位置有关。具体来说,越靠近查询链的起始位置的设备通常具有较高的优先级,而越靠近链的末尾位置的设备优先级较低。 优点: 简单实现&am…...
后端项目实战--瑞吉外卖项目软件说明书
瑞吉外卖项目软件说明书 一、项目概述 瑞吉外卖项目是一个外卖服务平台,用户可以通过该平台浏览餐厅菜单、下单、支付以及追踪订单状态。产品原型就是一款产品成型之前的一个简单的框架,就是将页面的排版布局展现出来,使产品得初步构思有一…...
LeetCode | 27.移除元素
这道题的思路和26题一模一样,由于要在元素组中修改,我们可以设置一个index表示目前要修改原数组的第几位,由于遍历,访问原数组永远会在我们修改数组之前,所以不用担心数据丢失的问题,一次遍历数组ÿ…...
为什么要选择AWS?AWS的优势有哪些?
亚马逊云服务器(Amazon Web Services,AWS)是全球领先的云计算服务提供商之一,其提供的云服务器是在全球范围内可用的弹性计算服务。对于很多用户来说,他们可能会担心亚马逊云服务器是否会对服务器的使用进行限制。以下…...
【Intel CVPR 2024】通过图像扩散模型生成高质量360度场景,只需要一个语言模型
在当前人工智能取得突破性进展的时代,从单一输入图像生成全景场景仍是一项关键挑战。大多数现有方法都使用基于扩散的迭代或同步多视角内绘。然而,由于缺乏全局场景布局先验,导致输出结果存在重复对象(如卧室中的多张床࿰…...
postman教程-21-Newman运行集合生成测试报告
上一小节我们Postman Newman的安装方法,本小节我们讲解一下Postman Newman的具体使用方法。 使用Newman运行集合 1、导出Postman集合: 在Postman中,选择你想要运行的集合,然后点击“导出”按钮,选择导出为“Collect…...
基于条件谱矩的时间序列分析(以轴承故障诊断为例,MATLAB)
谱矩方法可以对数据的表面形貌做较为细致的描述.它以随机过程为理论基础,用各阶谱矩及统计不变量等具体的参数表征表面的几何形态,算术平均顶点曲率是一种基于四阶谱矩的统计不变量。 鉴于此,采用条件谱矩方法对滚动轴承进行故障诊…...
ArcGIS Pro 3.0加载在线高德地图
1、打开ArcGIS Online官网,登录自己的账号,登录后效果如下图所示 官网地址:https://www.arcgis.com/home/webmap/viewer.html 2、点击Add,选择Add Layer from Web,如下图所示 3、在显示的Add Layer from Web页面内&am…...
服务器防漏扫,主机加固方案来解决
什么是漏扫? 漏扫是漏洞扫描的简称。漏洞扫描是一种安全测试方法,用于发现计算机系统、网络或应用程序中的潜在漏洞和安全弱点。通过使用自动化工具或软件,漏洞扫描可以检测系统中存在的已知漏洞,并提供相关的报告和建议…...
复古传奇手游排行榜第一名/宁波超值关键词优化
历史回顾 为了能够更好的理解什么是DevOps,我们很有必要对当时还只有程序员(此前还没有派生出开发者,前台工程师,后台工程师之类)这个称号存在的历史进行一下回顾。 如编程之道中所言: 老一辈的程序员是神秘且深奥的。我们没法揣摩…...
做网站赚不了钱/茂名百度seo公司
思仿近期文章(上滑更多)● 继电保护主要功能原理与知识要点● 电流互感器基础及其试验测试技术● 电力系统故障分析的原理和计算方法● 电力系统仿真分析及安全防御专家 — 汤涌● 快速学会启停机保护整定计算原则● 电力系统安全稳定控制装置运行维护注意事项● “自知之明&am…...
怀远做网站电话/汕头seo排名收费
我正在构建一个简单的工具,它将根据HTML表单输入组装一个字符串。来自HTML表单的某些变量没有得到回应但是,两个变量没有按预期拉入字符串。下面是HTML表单:Subject line:Email TypeAdvocacyFundraisingNewsletterEventCultivationCampaignCa…...
济南优化官网公司/东莞seo关键词
[url]http://blog.csdn.net/ll136078/article/details/12747403[/url]安 装PostgreSQL数据库之后,默认是只接受本地访问连接。如果想在其他主机上访问PostgreSQL数据库服务器,就需要进行相应的配置。 配置远 程连接PostgreSQL数据库的步骤很简单…...
政府门户网站建设项目招标采购/网站推广培训
什么是控制文件 oracle控制文件是一个跟踪数据库的物理组成的二进制文件,仅与一个数据库相关联,每个数据库有唯一的控制文件,可以维护多个相同的拷贝。控制文件是oracle数据库用来查找数据库文件,并从总体上管理漱口状态的根文件。…...
python做网站的开发/百度怎么做广告
pg中删除表中记录后,通过vacuum命令可以回收那些dead tulpe占用的空间。那么vacuum具体是怎么回收空间的呢?空间回收之后会影响原先表上索引的正常使用吗? 要弄清楚这些问题,我们那首先要知道在pg中heap page内部的空间分配是什么…...