迭代结构化模板的参数包
Iterating over a parameter pack of structured templates
我希望能够将可变参数函数传递给多个结构化模板(代表传感器读数),并让它遍历这些结构的成员。我的模板和初始值设定项如下所示:
template <typename T>
struct reading_t {
const char *name;
const char *fmt;
const char *units;
T value;
};
static reading_t<float> longitude = {"Longitude", "%f", "deg", 0.0};
static reading_t<uint32_t> altitude = {"Altitude", "%d", "m", 0};
static reading_t<float> heading = {"Heading", "%f", "deg", 0};
我的最终目标只是一个函数,它吐出一个 reading_t.name
的串联列表,所以来自 C 我从一个典型的可变参数函数开始,它看起来像这样不幸的:
char *concat_readings(char *b, reading_t<auto> *reading...) {
va_list args;
...
}
char buffer[256] = "";
concat_readings(&buffer, &longitude, &altitude, &latitude NULL);
// out << buffer; // Longitude, Altitude, Heading
现在我迷失在 C++ 参数包等的汤里了
PS:我使用的是嵌入式系统,所以不幸的是无法访问标准库。
如果我理解正确......并且如果你想使用类似 printf()
的格式......我想你正在寻找一些东西(假设你标记了 C++14)
template <typename ... Args>
char * concat_readings (char * buffer, Args const & ... as)
{
using unused = int[];
char * b { buffer };
(void)unused { 0, (std::sprintf(b,
std::string{"%s "}.append(as.fmt).append(" %s; ").c_str(),
as.name, as.value, as.units), b+=std::strlen(b), 0)... };
return buffer;
}
如果能用C++17,可以稍微简化一下:
template <typename ... Args>
char * concat_readings (char * buffer, Args const & ... as)
{
char * b { buffer };
((std::sprintf(b,
std::string{"%s "}.append(as.fmt).append(" %s; ").c_str(),
as.name, as.value, as.units), b+=std::strlen(b)), ... );
return buffer;
}
通话中
char buffer[520];
concat_readings(buffer, longitude, altitude, heading);
std::cout << buffer << '\n';
你得到
Longitude 0.000000 deg; Altitude 0 m; Heading 0.000000 deg;
显然,如果您不能使用 std::string
、std::strlen()
和 std::sprintf()
,则必须用等效的东西替换它们。
如果我没理解错,你想在 concat_readings 中使用参数包连接读数的名称,那么你可以进行下一步。
你可以完全不使用任何标准库包含,只需实现你自己的字符串管理功能,如strcat/strcpy。事实上,您可以在嵌入式系统上使用带有模板的完全可用的 C++ 功能,甚至不包括单个标准库头文件,我在我的非常大的嵌入式项目中就是这样做的。 C++ 的模板和其他功能不需要任何标准头文件。也许您还想使用 -fno-exceptions
在 GCC 中禁用异常,如果您根本不使用异常,则 C++ 功能不需要异常。
我使用 strcpy/strcat/printf 只是为了举例,您必须自己使用和实现这些功能的版本。
#include <cstdio>
#include <cstring>
#include <cstdint>
template <typename T>
struct reading_t {
const char *name;
const char *fmt;
const char *units;
T value;
};
template <typename R>
char * concat_readings(char * buf, reading_t<R> const & reading) {
strcat(buf, reading.name);
return buf;
}
template <typename R, typename ... RT>
char * concat_readings(char * buf, reading_t<R> const & reading,
reading_t<RT> const & ... readings) {
strcat(buf, reading.name);
strcat(buf, ", ");
concat_readings(buf, readings...);
return buf;
}
int main() {
static reading_t<float> longitude = {"Longitude", "%f", "deg", 0.0};
static reading_t<uint32_t> altitude = {"Altitude", "%d", "m", 0};
static reading_t<float> heading = {"Heading", "%f", "deg", 0};
char buf[256] = {};
concat_readings(buf, longitude, altitude, heading);
printf("%s", buf);
}
输出:
Longitude, Altitude, Heading
我首先错误地实现了你函数的 malloc/free 变体,误读了你的问题。因此,下面提供第一个实现只是为了举例。
假设你可以使用malloc/free,否则你可以自己实现内存分配,我使用malloc/free作为例子。
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cstdint>
template <typename T>
struct reading_t {
const char *name;
const char *fmt;
const char *units;
T value;
};
char * concat_readings() {
char * bp = (char*)malloc(1);
bp[0] = 0;
return bp;
}
template <typename R, typename ... RT>
char * concat_readings(reading_t<R> const & reading, reading_t<RT> const & ... readings) {
char * tail = concat_readings(readings...);
int const bl = strlen(reading.name), tl = strlen(tail);
char * bp = (char*)malloc(bl + tl + 1);
strcpy(bp, reading.name);
strcat(bp, tail);
free(tail);
return bp;
}
int main() {
static reading_t<float> longitude = {"Longitude", "%f", "deg", 0.0};
static reading_t<uint32_t> altitude = {"Altitude", "%d", "m", 0};
static reading_t<float> heading = {"Heading", "%f", "deg", 0};
char * concat = concat_readings(longitude, altitude, heading);
printf("%s", concat);
free(concat);
}
输出:
LongitudeAltitudeHeading
我希望能够将可变参数函数传递给多个结构化模板(代表传感器读数),并让它遍历这些结构的成员。我的模板和初始值设定项如下所示:
template <typename T>
struct reading_t {
const char *name;
const char *fmt;
const char *units;
T value;
};
static reading_t<float> longitude = {"Longitude", "%f", "deg", 0.0};
static reading_t<uint32_t> altitude = {"Altitude", "%d", "m", 0};
static reading_t<float> heading = {"Heading", "%f", "deg", 0};
我的最终目标只是一个函数,它吐出一个 reading_t.name
的串联列表,所以来自 C 我从一个典型的可变参数函数开始,它看起来像这样不幸的:
char *concat_readings(char *b, reading_t<auto> *reading...) {
va_list args;
...
}
char buffer[256] = "";
concat_readings(&buffer, &longitude, &altitude, &latitude NULL);
// out << buffer; // Longitude, Altitude, Heading
现在我迷失在 C++ 参数包等的汤里了
PS:我使用的是嵌入式系统,所以不幸的是无法访问标准库。
如果我理解正确......并且如果你想使用类似 printf()
的格式......我想你正在寻找一些东西(假设你标记了 C++14)
template <typename ... Args>
char * concat_readings (char * buffer, Args const & ... as)
{
using unused = int[];
char * b { buffer };
(void)unused { 0, (std::sprintf(b,
std::string{"%s "}.append(as.fmt).append(" %s; ").c_str(),
as.name, as.value, as.units), b+=std::strlen(b), 0)... };
return buffer;
}
如果能用C++17,可以稍微简化一下:
template <typename ... Args>
char * concat_readings (char * buffer, Args const & ... as)
{
char * b { buffer };
((std::sprintf(b,
std::string{"%s "}.append(as.fmt).append(" %s; ").c_str(),
as.name, as.value, as.units), b+=std::strlen(b)), ... );
return buffer;
}
通话中
char buffer[520];
concat_readings(buffer, longitude, altitude, heading);
std::cout << buffer << '\n';
你得到
Longitude 0.000000 deg; Altitude 0 m; Heading 0.000000 deg;
显然,如果您不能使用 std::string
、std::strlen()
和 std::sprintf()
,则必须用等效的东西替换它们。
如果我没理解错,你想在 concat_readings 中使用参数包连接读数的名称,那么你可以进行下一步。
你可以完全不使用任何标准库包含,只需实现你自己的字符串管理功能,如strcat/strcpy。事实上,您可以在嵌入式系统上使用带有模板的完全可用的 C++ 功能,甚至不包括单个标准库头文件,我在我的非常大的嵌入式项目中就是这样做的。 C++ 的模板和其他功能不需要任何标准头文件。也许您还想使用 -fno-exceptions
在 GCC 中禁用异常,如果您根本不使用异常,则 C++ 功能不需要异常。
我使用 strcpy/strcat/printf 只是为了举例,您必须自己使用和实现这些功能的版本。
#include <cstdio>
#include <cstring>
#include <cstdint>
template <typename T>
struct reading_t {
const char *name;
const char *fmt;
const char *units;
T value;
};
template <typename R>
char * concat_readings(char * buf, reading_t<R> const & reading) {
strcat(buf, reading.name);
return buf;
}
template <typename R, typename ... RT>
char * concat_readings(char * buf, reading_t<R> const & reading,
reading_t<RT> const & ... readings) {
strcat(buf, reading.name);
strcat(buf, ", ");
concat_readings(buf, readings...);
return buf;
}
int main() {
static reading_t<float> longitude = {"Longitude", "%f", "deg", 0.0};
static reading_t<uint32_t> altitude = {"Altitude", "%d", "m", 0};
static reading_t<float> heading = {"Heading", "%f", "deg", 0};
char buf[256] = {};
concat_readings(buf, longitude, altitude, heading);
printf("%s", buf);
}
输出:
Longitude, Altitude, Heading
我首先错误地实现了你函数的 malloc/free 变体,误读了你的问题。因此,下面提供第一个实现只是为了举例。
假设你可以使用malloc/free,否则你可以自己实现内存分配,我使用malloc/free作为例子。
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cstdint>
template <typename T>
struct reading_t {
const char *name;
const char *fmt;
const char *units;
T value;
};
char * concat_readings() {
char * bp = (char*)malloc(1);
bp[0] = 0;
return bp;
}
template <typename R, typename ... RT>
char * concat_readings(reading_t<R> const & reading, reading_t<RT> const & ... readings) {
char * tail = concat_readings(readings...);
int const bl = strlen(reading.name), tl = strlen(tail);
char * bp = (char*)malloc(bl + tl + 1);
strcpy(bp, reading.name);
strcat(bp, tail);
free(tail);
return bp;
}
int main() {
static reading_t<float> longitude = {"Longitude", "%f", "deg", 0.0};
static reading_t<uint32_t> altitude = {"Altitude", "%d", "m", 0};
static reading_t<float> heading = {"Heading", "%f", "deg", 0};
char * concat = concat_readings(longitude, altitude, heading);
printf("%s", concat);
free(concat);
}
输出:
LongitudeAltitudeHeading