posts - 225, comments - 62, trackbacks - 0, articles - 0
   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

在C++判断字符串字面量

Posted on 2014-09-26 12:50 魔のkyo 阅读(359) 评论(0)  编辑 收藏 引用
实验环境
Windows, Visual Studio 2013
Linux, g++ 4.7.0
实现一个函数is_string_literal判断给定的字符串是否字符串字面量。
需要区分的值有如下种类:
字符串字面量 右值
char* 左值/右值
const char* 左值/右值
char [] 右值
const char[] 右值
要写出这样的函数是很困难的,在我测试的编译器上应该是不可能完成的,但是可以通过宏实现在编译时判断
#define IS_STRING_LITERAL(str) \
    (std::is_convertible<decltype(str), const char *>::value && \
    !std::is_rvalue_reference<decltype(str)>::value && \
    !std::is_pointer<decltype(str)>::value && \
    !std::is_array<decltype(str)>::value && \
    !std::is_class<decltype(str)>::value)
这种实现的限制是很大的,如果想在一个模板函数
template <typename T>
void func(const T& obj)
{
    //...
}
中判断obj是否是字符串字面量,上面的宏将不能工作。
但是如果将传入值的类型做一些限制,只要舍弃const char[],是可以通过函数重载实现is_string_literal的。
区分的值有如下:
字符串字面量 右值
char* 左值/右值
const char* 左值/右值
char [] 右值
const char[] 右值
// 这个函数会接收 char* 左值/右值 和 char []
bool is_string_literal(char* str)
{
    return false;
}
// 这个函数会接收 const char* 左值
bool is_string_literal(const char*& str)
{
    return false;
}
// 这个函数会接收 字符串字面量 const char[]
template <int N>
bool is_string_literal(const char(&str)[N])
{
    return true;
}
// 这个函数会接收 const char* 右值
template <typename T>
bool is_string_literal(const T& obj)
{
    return false;
}
reference

完整测试代码

#define _CRT_SECURE_NO_WARNINGS

#include 
<iostream>
#include 
<cstdio>
#include 
<string>
#include 
<cstring>
#include 
<typeinfo>
#include 
<cassert>
using namespace std;

bool is_string_literal(char* str)
{
    
return false;
}

bool is_string_literal(const char*& str)
{
    
return false;
}

template 
<int N>
bool is_string_literal(const char(&str)[N])
{
    
return true;
}

template 
<typename T>
bool is_string_literal2(const T& obj)
{
    typedef 
int _not_a_string[0];
    
return false;
}

bool is_string_literal2(const char* str)
{
    
return false;
}

template 
<typename T>
bool is_string_literal(const T& obj)
{
    
return is_string_literal2(obj);
}

#define IS_STRING_LITERAL(obj) \
    (std::is_convertible
<decltype(obj), const char *>::value && \
    
!std::is_rvalue_reference<decltype(obj)>::value && \
    
!std::is_pointer<decltype(obj)>::value && \
    
!std::is_array<decltype(obj)>::value && \
    
!std::is_class<decltype(obj)>::value)

char* func_pchar()
{
    
static char* str = (char*)"char* r-value";
    
return str;
}

const char* func_cpchar()
{
    
static const char* str = "const char* r-value";
    
return str;
}

#define ASSERT_TRUE(P) assert(P)
#define ASSERT_FALSE(P) assert(!(P))

int main()
{
    ASSERT_TRUE(is_string_literal(
"string literal"));

    
char* p = new char[32];
    strcpy(p, 
"char* l-value");
    ASSERT_FALSE(is_string_literal(p));
    delete[] p;

    ASSERT_FALSE(is_string_literal(func_pchar()));

    
const char* q = "const char* l-value";
    ASSERT_FALSE(is_string_literal(q));

    ASSERT_FALSE(is_string_literal(func_cpchar()));

    
char str1[] = "char[]";
    ASSERT_FALSE(is_string_literal(str1));

    
const char str2[] = "const char[]";
    
//ASSERT_FALSE(is_string_literal(str2));
}

只有注册用户登录后才能发表评论。