区分字符串文字和运行时生成的字符串的方法
Ways to distinguish string literal and runtime generated string
假设我有一个以字符串为输入的函数:
SomeOutputType f_impl(const char* s);
大多数调用站点只使用字符串文字作为输入,例如f("Hello, world")
。假设我已经实现了以下函数来计算编译时的结果
template <char...> SomeOutputType f_impl();
我的问题是,有没有办法让像f("Hello, world")
这样的调用站点调用模板化表单,而像string s="Hello, world"; f(s.c_str());
这样的通用调用站点调用通用表单?为了澄清,auto s = "Hello, world"; f(s);
不必调用模板化表单,因为s
现在是一个变量,不再是编译时常数。
这个问题的一个有用的例子是优化printf
。在大多数情况下,format
将是字符串文字,因此可以在编译时做很多事情来优化,而不是在运行时解析format
。
否,像"foo"
这样的字符串文字的类型为const char[S + 1]
,其中S
是您写入的字符数。它的行为就像一个没有特殊规则的那种类型的数组。
在C++03中,有一条特殊的规则,规定字符串文字可以转换为char*
。这让你可以说
#define isStringLiteral(X)
isConvertibleToCharStar(X) && hasTypeConstCharArray(X)
例如,isStringLiteral(+"foo")
将产生false
,而isStringLiteral("foo")
将产生true。即使是这种可能性也不允许您调用带有字符串文字参数的函数,并且行为不同。
C++11删除了特殊的转换规则,字符串文字的行为与任何其他数组一样。在C++11中,作为一个肮脏的黑客,你可以编写一些宏,匹配一些简单的字符串文字,而不需要处理转义序列
constexpr bool isStringLiteral(const char *x, int n = 0) {
return *x == '"' ?
n == 0 ?
isStringLiteral(x + 1, n + 1)
: !*(x + 1)
: (*x && n != 0 && isStringLiteral(x + 1, n + 1));
}
#define FastFun(X)
(isStringLiteral(#X) ? fConstExpr(X, sizeof(X) - 1) : f(X))
虽然我还没有测试过这一点,但我认为如果您只声明函数constexpr并进行高度优化编译,编译器将尽可能在编译时进行计算。作为奖励,您不需要编写两次代码。另一方面,您必须以constexpr样式编写一次。
如果我正确理解了这个问题,我实际上认为使用函数重载可以实现这样的事情。这是一篇展示基本思想的文章。在你的情况下,我认为有以下两个过载就足够了:
void f(char const *);
template<unsigned int N>
void f(char const (&)[N]);
当字符串是字符串文字时,应该调用后者,其他时候调用后者。如果编译器足够擅长优化,那么对后者的调用可以在编译时进行评估。
编辑:
好吧,上面的解决方案不起作用让我很困扰,所以我做了一些尝试,我想我想出了一个解决方案:
#include <string>
#include <boost/utility/enable_if.hpp>
template<typename T>
struct is_string_literal {
enum { value = false };
};
template<unsigned int N>
struct is_string_literal<char const (&)[N]> {
enum { value = true };
};
template<typename T>
typename boost::disable_if<is_string_literal<T> >::type
foo(T) {
std::cout << "foo1" << std::endl;
}
template<int N>
void foo(char const (&)[N]) {
std::cout << "foo2" << std::endl;
}
int main( ) {
std::string bar = "blah";
char const str[] = "blah";
foo(str);
foo("blah");
foo(bar.data());
}
输出(在GCC 4.4和-O3上)为:
foo2
foo2
foo1
我承认,我不完全理解为什么以前的解决方案不起作用。也许我不完全理解过载解决方案的某些方面。
- 有哪些有效的方法可以消除一组 100 万个字符串>重复数据?
- 在 c++ 中对类中的 c 字符串动态数组进行排序的最佳方法是什么?
- 具有字符串化的可变参数宏的现代/通用方法
- 接收字符串并使用它来调用方法C++
- 如何分隔字符串并将标记传递给方法
- 是否有通用方法可以找到任何以 null 结尾的字符串的长度?
- 当映射包含字符串向量作为值时,从值中获取键的有效方法
- 在 C++11 中字符串化变量名称的替代方法
- 连接和压缩标准::vector<std::字符串的最佳方法>
- Esp8266 & Nodemcu:返回请求字符串的方法
- 将位字符串转储到二进制文件的最佳方法是什么
- 有没有一种 STL 方法可以找到字符串的所有排列,给出一个以 C++ 为单位的大小?
- 如何将字符串从 C++/CLI 方法返回到调用它的非托管C++
- 返回混合 \ 和 / 的文件系统路径字符串方法
- VS 链接器失败,标准::字符串方法出现"object already exists"错误
- Lua:为自定义用户数据提供一个字符串方法
- 语法错误字符串方法C++
- 返回原始子字符串的子字符串方法
- 为什么我不能在C++中使用这种方法与"char"而不是"字符串"方法?
- 如何使c++字符串函数的行为像Java和c#字符串方法