C++小知识:不要去做编译器的工作
背景
C++ 是一个庞大的语言,语法实在复杂。由于各种优化等操作,编译器已经变得越来越强大,并且一些操作也很难手动实现。然而,很多 C++ 开发人员容易错误地尝试手动实现一些简单的编译器功能(示例包括手写字符串分割、手写代码验证、手写类型推断等)。本文会通过两个示例说明为什么需要避免做编译器工作。
示例一:手写类型推断
首先我们看一个简单的例子:
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
这里使用了 decltype
实现了类型推导,并返回了两个模板参数的和。但是,有一些开发人员会尝试手动实现类型推断:
template<typename T, typename U>
auto add(T t, U u) {
if (std::is_same<T, int>::value && std::is_same<U, int>::value) {
return t + u;
} else if (std::is_same<T, double>::value && std::is_same<U, double>::value) {
return t + u;
} else if (std::is_same<T, float>::value && std::is_same<U, float>::value) {
return t + u;
} else if (std::is_same<T, char*>::value && std::is_same<U, char*>::value) {
return std::string(t) + std::string(u);
} else {
//...
}
}
这种手动实现类型推导的代码实现起来非常麻烦,而且还需要识别和处理各种不同的类型。如果有新的类型需要处理,开发人员还需要手动添加代码。这就是为什么我们应该使用编译器提供的类型推导能力而不是自己手动实现。
示例二:手写字符串分割
接下来我们看另一个例子:手写实现 C++ 的字符串分割。
#include <vector>
#include <string>
std::vector<std::string> split(const std::string& s, char delimiter)
{
std::vector<std::string> tokens;
std::string token;
for (char c : s) {
if (c == delimiter) {
tokens.push_back(token);
token.clear();
} else {
token += c;
}
}
tokens.push_back(token);
return tokens;
}
这种代码可以手动将字符串分割成一个个的子字符串,但是,C++ 标准库已经为我们提供了 std::string::find()
和 std::string::substr()
等方法,可以非常方便地实现字符串分割。
#include <vector>
#include <string>
std::vector<std::string> split(const std::string& s, char delimiter)
{
std::vector<std::string> tokens;
std::size_t start = 0;
std::size_t end = s.find(delimiter, start);
while (end != std::string::npos) {
tokens.push_back(s.substr(start, end - start));
start = end + 1;
end = s.find(delimiter, start);
}
tokens.push_back(s.substr(start));
return tokens;
}
这种方法比手动实现字符串分割更容易实现,也更容易阅读和理解。
总结
在 C++ 开发中,我们不应该尝试手动实现一些编译器在正确执行上下文的情况下自动完成的工作。以示例一中的类型推断和示例二中的字符串分割为例,它们已经被编译器以更优秀的方式高效地实现了。我们应该充分利用 C++ 标准库提供的现成功能,并避免重复造轮子,这样我们的代码会变得更加简洁、高效、易于维护。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++小知识:不要去做编译器的工作 - Python技术站