实验环境
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));
}