我想出了以下解决方案:
类型生成为:
const char foo_str [] = "foo";
struct X
{
static const char *name() { return foo_str; }
enum{ name_size = sizeof(foo_str) };
};
这里的关键是我们在编译时就知道它的名字的长度。这允许我们计算类型列表中名称的总长度:
template<typename list>
struct sum_size
{
enum
{
value = list::head::name_size - 1 +
sum_size<typename list::tail>::value
};
};
template<>
struct sum_size<nil>
{
enum { value = 0 };
};
在编译时知道总长度,我们可以为字符串的连接分配适当大小的静态缓冲区 - 所以不会有任何动态分配:
static char result[sum_size<list>::value + 1];
该缓冲区应在运行时填充,但只填充一次,并且该操作非常便宜(比以前使用字符串动态分配及其递归连接的解决方案快得多):
template<typename list>
const char *concate_names()
{
static char result[sum_size<list>::value + 1];
static bool calculated = false;
if(!calculated)
{
fill_string<list>::call(result);
calculated = true;
}
return result;
}
这是完整的代码:
Coliru 上的现场演示
#include <algorithm>
#include <iostream>
using namespace std;
/****************************************************/
#define TYPE(X) \
const char X ## _str [] = #X; \
struct X \
{ \
static const char *name() { return X ## _str; } \
enum{ name_size = sizeof(X ## _str) }; \
}; \
/**/
/****************************************************/
struct nil {};
template<typename Head, typename Tail = nil>
struct List
{
typedef Head head;
typedef Tail tail;
};
/****************************************************/
template<typename list>
struct sum_size
{
enum { value = list::head::name_size - 1 + sum_size<typename list::tail>::value };
};
template<>
struct sum_size<nil>
{
enum { value = 0 };
};
/****************************************************/
template<typename list>
struct fill_string
{
static void call(char *out)
{
typedef typename list::head current;
const char *first = current::name();
fill_string<typename list::tail>::call
(
copy(first, first + current::name_size - 1, out)
);
}
};
template<>
struct fill_string<nil>
{
static void call(char *out)
{
*out = 0;
}
};
/****************************************************/
template<typename list>
const char *concate_names()
{
static char result[sum_size<list>::value + 1];
static bool calculated = false;
if(!calculated)
{
fill_string<list>::call(result);
calculated = true;
}
return result;
}
/****************************************************/
TYPE(foo)
TYPE(bar)
TYPE(baz)
typedef List<foo, List<bar, List<baz> > > foo_list;
int main()
{
cout << concate_names<foo_list>() << endl;
}
输出是:
foobarbaz
PS你如何使用连接字符串?也许我们根本不需要生成连接字符串,减少数据空间需求。
例如,如果您只需要打印字符串 - 那么
template<typename list>
void print();
就足够了。但缺点是在减少数据大小的同时 - 这可能会导致代码大小增加。