#include <iostream>
#include <type_traits>
// 模板类用于在编译期计算字符在字符串中的位置
template <char c, const char* str, size_t index = 0>
struct CharPosition {
static constexpr size_t value =
(str[index] == '\0')? -1 :
(str[index] == c)? index :
CharPosition<c, str, index + 1>::value;
};
// 主模板特化,用于处理字符串结束的情况
template <char c, const char* str>
struct CharPosition<c, str, std::char_traits<char>::length(str)> {
static constexpr size_t value = -1;
};
int main() {
const char* testStr = "Hello, World!";
constexpr size_t pos = CharPosition<'o', testStr>::value;
std::cout << "Position of 'o' in the string: " << pos << std::endl;
return 0;
}
字符常量与字符串常量初始化方式的特殊性
- 字符常量:在C++ 模板元编程中,字符常量直接使用单引号括起来,如
'a'
。它们在编译期是一个 char
类型的常量表达式,可以直接作为模板参数传递。
- 字符串常量:字符串常量在C++ 中以
const char*
类型表示,如 "Hello"
。在模板元编程中传递字符串常量时,需要注意其在编译期的常量性。因为字符串常量本身是一个指针,指向静态存储区的字符数组。为了在模板元编程中使用,需要确保其在编译期的可用性,这里使用 const char*
作为模板参数传递。
避免编译期错误
- 边界检查:通过模板特化处理字符串结束的情况,如上述代码中
CharPosition<c, str, std::char_traits<char>::length(str)>
特化模板,避免在访问字符串超出其长度时导致编译错误。
- 类型匹配:确保模板参数类型与模板定义中的类型匹配。例如,字符常量必须是
char
类型,字符串常量必须是 const char*
类型。
- 常量表达式:模板参数必须是常量表达式,以确保在编译期能够求值。例如,传递的字符串常量指针必须指向一个编译期已知的常量字符串。