我有这个日志系统,我正在寻找一些字符串操作的快捷方式.
日志系统通过功能宏使用,然后转发到单个函数调用.例如#define Warning(...) LogMessage(eWarning, __VA_ARGS__);.
然后LogMessage snprintf进入一个新的缓冲区,然后将该消息提供给碰巧安装的任何日志目标; printf,OutputDebugString等
不幸的是,我遇到了一个问题,即我们所拥有的缓冲区不够大,因此输出会被截断.我还意识到,如果输出消息中包含百分比符号,则此方法将失败,因为snprintf将尝试处理va_args.最后,因为我们的大多数日志消息都不使用va_args,所以复制字符串只是为了将它呈现给记录器似乎很愚蠢.
那么 - 鉴于我的函数原型,我是否应该能够根据省略号的存在进行重载?换句话说,我是否可以假设我可以做以下事情:
LogMessage(LogLevel, const char* message, ...);
LogMessage(LogLevel, const char* message);
Run Code Online (Sandbox Code Playgroud)
我的谷歌尝试没有产生任何特别有用的东西(只是告诉我椭圆将匹配,如果没有别的,根据我的要求,没有任何匹配),我的初始实施只是给了我一个模糊的函数调用错误.
有了这个错误,我应该接受我不能这样做,但我想知道它是否只是我正在使用的编译器,或者我是否做错了.我可以达到类似的效果
// edited version of what I really have to remove our local APIs,
// please excuse minor errors
const char* message = NULL;
char buffer[512];
va_list args;
va_start(args, format);
if(strcmp(format, "%s") == 0) {
message = va_arg(args, const char*);
}
else if (strchr(format, '%') == NULL) {
message = format;
}
else …Run Code Online (Sandbox Code Playgroud) 我有一个类模板,我似乎无法弄清楚如何执行Variadic模板样式实例化.
这是迄今为止我正在寻找的"代码":
template<typename _Classname, typename... Args>
class CFunctorStartExT
{
friend class CXXFactory;
protected:
template<typename U>
CFunctorStartExT(typename U& _functor, Args&... args) :
m_Functor(_functor),
m_args(args)
{
}
virtual bool ProcessLoop(CSomeClass* pThread)
{
return m_Functor(pThread, m_args);
}
protected:
_Classname& m_Functor;
Args... m_args;
};
Run Code Online (Sandbox Code Playgroud)
显然这不会编译:).我们的想法是创建一个类,它可以在构造函数中存储传入的值(如果有的话......它可能只有_Classname/U定义),以便稍后可以检索它们以传递给另一个函数中的m_Functor.
第一:Variadic模板甚至可以在VS2010中完成吗?我只是error C2143: syntax error : missing ',' before '...'从行中的模板声明得到编译问题template<typename _Classname, typename... Args>
第二,我想要完成的事情可以做到吗?谢谢!
我有来自第三方C库的可变参数函数:
int func(int argc, ...);
Run Code Online (Sandbox Code Playgroud)
argc表示传递的可选参数的数量.我正在用一个计算参数数量的宏来包装它,如此处所示.为了方便阅读,这里是宏:
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
_61, _62, …Run Code Online (Sandbox Code Playgroud) 给定任意数量的包装,从每个包装中取出第一种类型,将它们放在一起.然后是每个包中的第二种类型,将它们放在一起等等......然后将它们全部合并.任何左撇子都会在他们之间重复这个过程.例如,使用整数表示不同类型以获得更好的可读性,
InterlacePacks<Pack<1 2 3 4>, Pack<5 6 7>, Pack<8 9 10 11 12>>::type
Run Code Online (Sandbox Code Playgroud)
会给
Pack<1 5 8 2 6 9 3 7 10 4 11 12>
Run Code Online (Sandbox Code Playgroud)
如果所有包只是相同的大小,则以下代码有效.我现在完全陷入对付"左结转"的时候,包是不同的尺寸.到目前为止,这是我的代码.我解释每个阶段,以便你知道我的计划是什么:
#include <iostream>
// First a helper to remove the first N types from a pack:
template <int, typename> struct RemoveHead;
template <typename Pack>
struct RemoveHead<0, Pack> { using type = Pack; };
template <template <typename...> class P, typename First, typename... Rest>
struct RemoveHead<0, P<First, Rest...>> { using type = …Run Code Online (Sandbox Code Playgroud) 我在Code :: Blocks中准备了一个简单的可变参数模板测试,但是我收到一个错误:
调用'OutputSizes()'没有匹配函数
这是我的源代码:
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename FirstDatatype, typename... DatatypeList>
void OutputSizes()
{
std::cout << typeid(FirstDatatype).name() << ": " << sizeof(FirstDatatype) << std::endl;
OutputSizes<DatatypeList...>();
}
int main()
{
OutputSizes<char, int, long int>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用GNU GCC -std=C++0x.使用-std=gnu++0x没有区别.
我有一个可变参数模板,表示函数的参数列表,例如:
void myFunc (int,int,std::string) { }
template<typename... Args> class MyTemplateClass { };
...
MyTemplateClass<int,int,std::string> myConcrete; // for use with myFunc later
Run Code Online (Sandbox Code Playgroud)
有没有什么方法可以从decltype(func)中提取参数类型来节省必须手动编写它们,例如:
MyTemplateClass<something_like_decltype(myFunc)> myConcrete;
Run Code Online (Sandbox Code Playgroud)
即在这种情况下decltype会给我"void(int,int,string)"但是有没有办法只提取"int,int,string"部分以便在变量模板中使用?
注意:我必须使用可变参数模板方法,因为在模板中它依次对每个参数类型执行处理.
我有一个简单的模板结构,将字符串与值相关联
template<typename T> struct Field
{
std::string name; T self;
}
Run Code Online (Sandbox Code Playgroud)
我有一个函数,我想接受任何类型的1个或多个字段,而字段可能是不同类型的,所以我使用的是std::initializer_list因为C++,据我所知,缺少类型的可变参数,无法确定可变参数的大小,并且必须至少有一个其他参数来确定从哪里开始.
问题是我不知道如何告诉它接受可能属于不同类型的字段.在Java中,我只会使用foo(Field<?> bar, Field<?>... baz),但C++缺少类型化的可变参数和通配符.我唯一的另一个想法是制作类型的参数
std::initializer_list<Field<void*>>,但这似乎是一个糟糕的解决方案......有更好的方法吗?
我正在尝试编译一个巨大的、世界知名的数值天气预报代码 - 主要用 Fortran 90 编写 -广泛且成功地使用cpp以及 PGI、Intel 和 gfortran。现在,我继承了一个版本,其中专家添加了数百个可变参数宏案例。他们使用 Intel 和fpp,这可能更以 Fortran 为中心,并且可以让一切正常工作。我需要使用 gfortran,但无法让cpp通过其新添加的内容来处理此代码。
问题的总体简化如下 -
预处理代码:
PRINT *, "Hello" // "Don"
#define adderv(...) (myadd(__VA_ARGS__))
sumv = adderv(1, 2, 3, 4, 5)
Run Code Online (Sandbox Code Playgroud)
使用不带该选项的cpp-traditional将处理可变参数宏,但不能处理 Fortran 连接:
$ cpp -P t.F90
PRINT *, "Hello"
sumv = (myadd(1, 2, 3, 4, 5))
Run Code Online (Sandbox Code Playgroud)
另一方面,使用-traditional标志处理串联,但不处理可变参数宏:
$ cpp -P -traditional t.F90
t.F90:2:0: error: syntax error in macro parameter list
#define adderv(...) (myadd(__VA_ARGS__))
^
PRINT …Run Code Online (Sandbox Code Playgroud) 我有一个关于重新启动可变参数列表(va_list)的问题.基本上我想做这样的事情:
void someFunc(char* fmt, ...) {
va_list ap;
va_start(fmt, ap);
otherFuncA(fmt, ap);
// restart ap
otherFuncB(fmt, ap);
// restart ap
...
va_end(ap);
return;
}
Run Code Online (Sandbox Code Playgroud)
现在我的问题是:如何重启ap?
请注意,这个问题与C++无关,但是C.
到目前为止,我找到了两种可能的解决方案,但我想知道哪一种是"正确的"或"最佳实践".
解决方案1:多重 va_start()
使用GCC7我可以替换线路
// restart ap
Run Code Online (Sandbox Code Playgroud)
在上面的例子中
va_end(ap);
va_start(fmt, ap);
Run Code Online (Sandbox Code Playgroud)
重置ap为第一个参数.但是,我不确定这是否真的是有效的代码,或者我很幸运,一些未定义的行为没有破坏结果.
解决方案2: va_copy()
另一个适用于GCC7的解决方案是初始化几个ap使用va_copy()类似的副本
void someFunc(char* fmt, ...) {
va_list ap1, ap2;
va_start(fmt, ap1);
va_copy(ap2, ap1);
otherFuncA(fmt, ap1);
otherFuncB(fmt, ap2);
va_end(ap1);
va_end(ap2);
return;
}
Run Code Online (Sandbox Code Playgroud)
这是有效的代码(imo),但由于现在有多个va_list实例需要复制,因此效率远低于第一个解决方案.
那么哪种解决方案最好?它是我上面提到的两个中的一个,还是完全不同的东西?
我正在使用实体组件系统编写一个简单的游戏。我的组件之一是NativeScriptComponent. 它包含我的脚本的实例。我的想法是,我可以NativeScriptComponent随时创建我的Bind任何类实现Scriptable接口。之后我的游戏的 OnUpdate 函数将自动实例化游戏中的所有脚本并调用它们的 OnUpdate 函数。
我的脚本可以有自己的不同构造函数,因此在绑定脚本时我需要将所有参数转发给它们。
考虑以下代码:
#include <iostream>
#include <memory>
#include <functional>
using namespace std;
struct Scriptable
{
virtual void OnUpdate() {};
};
struct MyScript : Scriptable
{
MyScript(int n) : value(n) {}
void OnUpdate() override {cout << value;}
int value;
};
struct NativeScriptComponent
{
unique_ptr<Scriptable> Instance;
function<unique_ptr<Scriptable>()> Instantiate;
template<typename T, typename ... Args>
void Bind(Args&&... args)
{
// (A)
Instantiate = [&args...]() { return make_unique<T>(forward<Args>(args)...); };
// (B) since …Run Code Online (Sandbox Code Playgroud)