时间:2019-03-08 标签:c++constexprconcatenatechar*
c++ constexpr concatenate char*
上下文:
在我的公司,我们基于 IDL 文件生成了很多类型。有些类型需要特殊的逻辑,因此它们是手工编码的,但遵循与生成的类型相同的模式。我们有一个所有类型都必须实现的函数,它是一个名称函数。这将 return 类型名称作为 char*
字符串,函数是 constexpr.
问题:
问题是关于可能包含嵌套 N 次的其他集合的集合。因此,我试图在编译时 连接两个或多个 char*
字符串 .
我想要实现的伪代码:
template <typename T>
constexpr char* name()
{
constexpr char* collectionName = "std::vector";
constexpr char* containedTypeName = name<T>();
return concat(collectionName, "<", containedTypeName, ">");
}
注:
有一些例子可以做这样的事情,但是是用 char[]
或使用静态变量完成的。
问题:
我如何制作一个 constexpr
函数,其中 return 一个 char*
在编译时由两个或多个连接的 char* 字符串组成?我绑定到 C++17。
从 constexpr 你不能 return 在那里构造的 char*...你必须 return 一些已知的编译时间(还有它的大小)常量。
一个可能的解决方案可能是这样的:
#include <cstring>
// Buffer to hold the result
struct NameBuffer
{
// Hardcoded 128 bytes!!!!! Carefully choose the size!
char data[128];
};
// Copy src to dest, and return the number of copied characters
// You have to implement it since std::strcpy is not constexpr, no big deal.
constexpr int constexpr_strcpy(char* dest, const char* src);
//note: in c++20 make it consteval not constexpr
template <typename T>
constexpr NameBuffer name()
{
// We will return this
NameBuffer buf{};
constexpr const char* collectionName = "std::vector";
constexpr const char* containedTypeName = "dummy";
// Copy them one by one after each other
int n = constexpr_strcpy(buf.data, collectionName);
n += constexpr_strcpy(buf.data + n, "<");
n += constexpr_strcpy(buf.data + n, containedTypeName);
n += constexpr_strcpy(buf.data + n, ">");
// Null terminate the buffer, or you can store the size there or whatever you want
buf.data[n] = '[=10=]';
return buf;
}
并且由于 returned char* 仅取决于您的情况下的模板参数,您可以创建模板化变量,并为它们创建一个 char*,它可以像任何其他 char* ...
编辑:
我刚刚意识到你的伪代码永远行不通!!在 name<T>()
中,您正在尝试调用 name<T>()
.
你必须重新设计这个!!!但!通过一些技巧,您可以在编译时以某种方式确定大小,例如:
#include <cstring>
#include <iostream>
template<std::size_t S>
struct NameBuffer
{
char data[S];
};
// Copy src to dest, and return the number of copied characters
constexpr int constexpr_strcpy(char* dest, const char* src)
{
int n = 0;
while((*(dest++) = *(src++))){ n++; }
return n;
}
// Returns the len of str without the null term
constexpr int constexpr_strlen(const char* str)
{
int n = 0;
while(*str) { str++; n++; }
return n;
}
// This template parameter does nothing now...
// I left it there so you can see how to create the template variable stuff...
//note: in c++20 make it consteval not constexpr
template <typename T>
constexpr auto createName()
{
constexpr const char* collectionName = "std::vector";
constexpr const char* containedTypeName = "dummy";
constexpr std::size_t buff_size = constexpr_strlen(collectionName) +
constexpr_strlen(containedTypeName) +
2; // +1 for <, +1 for >
/// +1 for the nullterm
NameBuffer<buff_size + 1> buf{};
/// I'm lazy to rewrite, but now we already calculated the lengths...
int n = constexpr_strcpy(buf.data, collectionName);
n += constexpr_strcpy(buf.data + n, "<");
n += constexpr_strcpy(buf.data + n, containedTypeName);
n += constexpr_strcpy(buf.data + n, ">");
buf.data[n] = '[=11=]';
return buf;
}
// Create the buffer for T
template<typename T>
static constexpr auto name_buff_ = createName<T>();
// point to the buffer of type T. It can be a function too as you wish
template<typename T>
static constexpr const char* name = name_buff_<T>.data;
int main()
{
// int is redundant now, but this is how you could use this
std::cout << name<int> << '\n';
return 0;
}
上下文:
在我的公司,我们基于 IDL 文件生成了很多类型。有些类型需要特殊的逻辑,因此它们是手工编码的,但遵循与生成的类型相同的模式。我们有一个所有类型都必须实现的函数,它是一个名称函数。这将 return 类型名称作为 char*
字符串,函数是 constexpr.
问题:
问题是关于可能包含嵌套 N 次的其他集合的集合。因此,我试图在编译时 连接两个或多个 char*
字符串 .
我想要实现的伪代码:
template <typename T>
constexpr char* name()
{
constexpr char* collectionName = "std::vector";
constexpr char* containedTypeName = name<T>();
return concat(collectionName, "<", containedTypeName, ">");
}
注:
有一些例子可以做这样的事情,但是是用 char[]
或使用静态变量完成的。
问题:
我如何制作一个 constexpr
函数,其中 return 一个 char*
在编译时由两个或多个连接的 char* 字符串组成?我绑定到 C++17。
从 constexpr 你不能 return 在那里构造的 char*...你必须 return 一些已知的编译时间(还有它的大小)常量。 一个可能的解决方案可能是这样的:
#include <cstring>
// Buffer to hold the result
struct NameBuffer
{
// Hardcoded 128 bytes!!!!! Carefully choose the size!
char data[128];
};
// Copy src to dest, and return the number of copied characters
// You have to implement it since std::strcpy is not constexpr, no big deal.
constexpr int constexpr_strcpy(char* dest, const char* src);
//note: in c++20 make it consteval not constexpr
template <typename T>
constexpr NameBuffer name()
{
// We will return this
NameBuffer buf{};
constexpr const char* collectionName = "std::vector";
constexpr const char* containedTypeName = "dummy";
// Copy them one by one after each other
int n = constexpr_strcpy(buf.data, collectionName);
n += constexpr_strcpy(buf.data + n, "<");
n += constexpr_strcpy(buf.data + n, containedTypeName);
n += constexpr_strcpy(buf.data + n, ">");
// Null terminate the buffer, or you can store the size there or whatever you want
buf.data[n] = '[=10=]';
return buf;
}
并且由于 returned char* 仅取决于您的情况下的模板参数,您可以创建模板化变量,并为它们创建一个 char*,它可以像任何其他 char* ...
编辑:
我刚刚意识到你的伪代码永远行不通!!在 name<T>()
中,您正在尝试调用 name<T>()
.
你必须重新设计这个!!!但!通过一些技巧,您可以在编译时以某种方式确定大小,例如:
#include <cstring>
#include <iostream>
template<std::size_t S>
struct NameBuffer
{
char data[S];
};
// Copy src to dest, and return the number of copied characters
constexpr int constexpr_strcpy(char* dest, const char* src)
{
int n = 0;
while((*(dest++) = *(src++))){ n++; }
return n;
}
// Returns the len of str without the null term
constexpr int constexpr_strlen(const char* str)
{
int n = 0;
while(*str) { str++; n++; }
return n;
}
// This template parameter does nothing now...
// I left it there so you can see how to create the template variable stuff...
//note: in c++20 make it consteval not constexpr
template <typename T>
constexpr auto createName()
{
constexpr const char* collectionName = "std::vector";
constexpr const char* containedTypeName = "dummy";
constexpr std::size_t buff_size = constexpr_strlen(collectionName) +
constexpr_strlen(containedTypeName) +
2; // +1 for <, +1 for >
/// +1 for the nullterm
NameBuffer<buff_size + 1> buf{};
/// I'm lazy to rewrite, but now we already calculated the lengths...
int n = constexpr_strcpy(buf.data, collectionName);
n += constexpr_strcpy(buf.data + n, "<");
n += constexpr_strcpy(buf.data + n, containedTypeName);
n += constexpr_strcpy(buf.data + n, ">");
buf.data[n] = '[=11=]';
return buf;
}
// Create the buffer for T
template<typename T>
static constexpr auto name_buff_ = createName<T>();
// point to the buffer of type T. It can be a function too as you wish
template<typename T>
static constexpr const char* name = name_buff_<T>.data;
int main()
{
// int is redundant now, but this is how you could use this
std::cout << name<int> << '\n';
return 0;
}