求问:C++98起合法的构造在C++20与C++23中是否有行为差异?
C版本检测程序:添加C23检测逻辑的方案
你写的这款靠C标准语法/行为差异检测版本的程序思路很有意思,目前的实现已经覆盖了C98到C20的区分逻辑。关于C23的检测,符合「自C98起合法但行为改变」的构造确实比较少见——毕竟C23的更新大多是新增特性,而非修改旧特性的既定行为。
不过还是有一个可以尝试的方向:
std::string::operator[]的行为变化
在C11到C20的标准里,std::string的operator[]允许传入等于字符串size()的索引,此时会返回指向末尾终止空字符的引用;但C++23修正了这一规则,明确要求索引必须严格小于size(),否则属于未定义行为。
需要注意的是,C98标准中operator[]使用等于size()的索引本身属于未定义行为,但很多主流编译器在C98模式下的处理逻辑和C11-20一致。如果你的目标编译器符合这个情况,可以用以下逻辑区分C23:
// ... 现有代码 ... } else { std::string s = "test"; bool is_cpp23 = false; try { char c = s[s.size()]; // C++11-20中此处会返回'\0',C++23中行为未定义,多数编译器会返回非'\0'值或崩溃 is_cpp23 = (c != '\0'); } catch (...) { is_cpp23 = true; } if (is_cpp23) { std::cout << "C++23" << std::endl; } else { std::cout << "C++20" << std::endl; } }
备选方案:__cplusplus宏
如果严格要求「自C98起合法」,目前最可靠的方式还是直接检查__cplusplus宏的值——C23对应的宏值是202302L,这虽然和你依托语法特性的初衷不符,但胜在稳定可靠:
// ... 现有代码 ... } else { #if __cplusplus >= 202302L std::cout << "C++23" << std::endl; #else std::cout << "C++20" << std::endl; #endif }
内容的提问来源于stack exchange,提问作者Purple P
相关产品推荐
相关产品推荐

