如何实现排除字符串字面量的左值判断特性及处理相关问题
解决字符串字面量被误判为左值的自定义特性实现
要解决这个问题,核心是区分普通左值引用和字符串字面量对应的字符数组左值引用——因为字符串字面量在万能引用推导中会被识别为const char(&)[N]类型的左值引用,而我们需要把这种特殊情况排除在"允许的左值"之外。
步骤1:定义辅助特性识别字符串字面量的左值引用
首先我们需要一个小特性,用来判断模板参数是否是const char数组的左值引用:
#include <type_traits> // 基础版本:默认不是const char数组的左值引用 template <typename T> struct is_const_char_array_lvalue_ref : std::false_type {}; // 特化版本:匹配const char[N]的左值引用 template <std::size_t N> struct is_const_char_array_lvalue_ref<const char(&)[N]> : std::true_type {}; // 方便使用的变量模板(C++14及以上) template <typename T> constexpr bool is_const_char_array_lvalue_ref_v = is_const_char_array_lvalue_ref<T>::value;
步骤2:实现自定义的my_lvalue_traits
接下来我们的核心特性就可以基于上面的辅助特性来实现:只有当模板参数是左值引用,且不是字符串字面量对应的字符数组左值引用时,value才为true:
template <typename T> struct my_lvalue_traits { static constexpr bool value = std::is_lvalue_reference_v<T> && // 首先确保是左值引用 !is_const_char_array_lvalue_ref_v<T>; // 排除字符串字面量的情况 }; // 同样提供变量模板方便使用 template <typename T> constexpr bool my_lvalue_traits_v = my_lvalue_traits<T>::value;
步骤3:验证模板函数的行为
现在把这个特性用到你的模板函数f中:
template <typename T> inline static void f(T&& arg) { static_assert(my_lvalue_traits<T>::value, "Only lvalue permitted"); // 其他代码... }
我们来测试几种场景:
- 普通左值传入:比如
int x = 42; f(x);,此时T被推导为int&,my_lvalue_traits<T>::value为true,静态断言通过。 - 字符串字面量传入:比如
f("hello");,此时T被推导为const char(&)[6],my_lvalue_traits<T>::value为false,静态断言触发错误,符合我们的要求。 - 右值传入:比如
f(123);,此时T被推导为int,my_lvalue_traits<T>::value为false,静态断言触发错误,保证了函数只接受左值。 - const char*左值传入:比如
const char* p = "test"; f(p);,此时T被推导为const char*&,不属于字符数组的左值引用,静态断言通过,这是合理的——因为p是一个左值变量,不是字符串字面量本身。
补充说明
如果你的编译器支持C17及以上,还可以用std::remove_reference_t结合std::is_array和std::is_same来简化辅助特性,但上面的写法兼容性更好,能覆盖C11及以上版本。
内容的提问来源于stack exchange,提问作者Speedding
相关产品推荐
相关产品推荐

