C++20中能否编写仅匹配字符串字面量的concept?
如何在C++20中编写仅匹配字符串字面量的Concept?
你提到的那个包装类确实存在缺陷:它的模板构造函数接受任意const char[N]类型的数组引用,不仅是字符串字面量,像静态存储期的命名字符数组(比如static const char arr[] = "test";)也能传入并通过编译。
要编写仅匹配字符串字面量的Concept,我们可以利用字符串字面量的核心特性:作为表达式时,它是纯右值(prvalue),而命名的数组变量是左值(lvalue)。以下是两种实现方案:
方案一:标准C++实现(近似匹配)
通过requires表达式检查参数能否绑定到数组右值引用,只有字符串字面量这类prvalue数组能满足条件:
#include <type_traits> template<typename T> concept StringLiteral = // 确保是数组类型,且元素是char(忽略cv限定) std::is_array_v<std::remove_reference_t<T>> && std::same_as<std::remove_cv_t<std::remove_extent_t<std::remove_reference_t<T>>>, char> && // 检查参数能作为右值数组引用传递(仅prvalue数组满足) requires(T&& s) { std::forward<T>(s) -> std::convertible_to<std::remove_reference_t<T>&&>; }; // 使用该Concept的函数 void takes_literal(StringLiteral auto lit) { // 此处lit的类型为const char (&)[N],仅接受字符串字面量 }
测试示例
int main() { takes_literal("hello world"); // 合法:字符串字面量是prvalue static const char arr[] = "test"; takes_literal(arr); // 编译失败:arr是lvalue,无法绑定到右值引用 const char* ptr = "invalid"; takes_literal(ptr); // 编译失败:不是数组类型 }
注意:这个方案无法阻止用户通过std::move传递constexpr静态数组(比如takes_literal(std::move(arr));),因为std::move会将左值转换为右值引用,从而绕过检查。
方案二:依赖编译器内置函数(严格匹配)
如果需要严格区分字符串字面量和所有其他数组,可以使用编译器提供的内置判断函数(比如GCC/Clang的__builtin_is_string_literal、MSVC的__is_string_literal),结合consteval函数实现精准检查:
#include <type_traits> // 利用编译器内置函数判断是否为字符串字面量 consteval bool is_string_literal(auto const& s) { return __builtin_is_string_literal(s); // GCC/Clang版本,MSVC可替换为__is_string_literal(s) } template<typename T> concept StringLiteral = std::is_array_v<std::remove_reference_t<T>> && std::same_as<std::remove_cv_t<std::remove_extent_t<std::remove_reference_t<T>>>, char> && // 在常量表达式中检查是否为字符串字面量 requires(T&& s) { requires is_string_literal(s); }; void takes_literal(StringLiteral auto lit) { // 使用lit }
这个方案能准确拒绝所有非字符串字面量的数组,包括被std::move转换的constexpr静态数组,但代价是丧失了部分编译器可移植性。
内容的提问来源于stack exchange,提问作者BeeOnRope
相关产品推荐
相关产品推荐

