如何通过"非平凡的可复制对象"进入GCC中的varargs函数

时间:2017-12-18 21:54:06

标签: c++ gcc

我有一个自定义记录器,它使用logger-> logf(format,...)样式的varargs方法进行记录。我有对象句柄,它们是指针的包装器。我有一个特殊的格式说明符来打印对象(使用像Java中的toString()方法)

"处理"不是可以轻易复制的#34;因为它们可以从许多输入类型构造,并且具有转换器转换操作符,它返回指向包含的对象类型的指针。 (类似于ComPtr<>)

在Windows C ++中,我可以传递句柄,varags方法可以看到指针。 GCC现在认为这是一个错误。句柄是" sizeof(void *)"

有没有办法让GCC在varags方法上允许这个? 有没有办法指定一个特殊的运算符xx()方法传递给varargs方法?

我有一个相当大的库,其中包含许多日志行,并使用operator +或operator<<重新执行所有这些日志行。将是一项繁重的家务活。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

好吧,如果看起来Variadic模板是我需要使用的,但我还没弄明白如何使它简单优雅。

算法的本质是

将对象或缓冲区放在堆栈上(理想情况下基于参数的数量) 将所有参数添加到对象。 在最后一个参数上,将它添加到对象中,并处理参数。

"递归"可变参数模板的本质是一个很好的方法来做这一点来弄清楚。

好的我点了一下子弹并重写了格式化程序部分以使用可变参数模板。确实需要3天。基本上它涉及到一个" Arg"具有所有原始类型和"类型"的联合的类由每个类型的构造函数重载设置的字段。

然后一个可变参数模板加载一个列表"传递给#34; vsprintf"的格式化程序的args。很好,因为有足够的信息是运行时类型安全。现在的问题是模板扩展有多少代码膨胀。正如他们所做的一切都是演员和" Arg"是一个固定的大小,它的构造函数只加载两个字段,类型和值。 GCC和MSC能否很好地优化所有这些,因此无法完全扩展可变参数模板。

template <typename... Args>
int writef(const wchar_t *fmt, ...) {
    FormatfArglist<sizeof...(Args)> arglist;
    FormatfArgBase::addArgs(arglist.args(), args...);
    return(vwritef(fmt, arglist));
}

template <typename First, typename... Rest> 
static void FormatfArgBase::addArgs(Arg *arglist, 
                              const First &first, const Rest &... rest) {            
    setArg(arglist,Arg(first));            
    if(sizeof... (Rest) > 0) {
        addArgs(++arglist, rest...); // recursive call using pack expansion syntax  
    }
}  

2 个答案:

答案 0 :(得分:0)

似乎C ++人员对旧C省略号的限制,实际上必须使用Variadic模板来获得全部功能。

所以我咬了一下子弹并重写了格式化程序部分以使用可变参数模板。确实需要3天。基本上它涉及到一个&#34; Arg&#34;具有所有原始类型和&#34;类型&#34;的联合的类由每个类型的构造函数重载设置的字段。

然后一个可变参数模板加载一个列表&#34;传递给#34; vsprintf&#34;的格式化程序的args。很好,因为有足够的信息是运行时类型安全。现在的问题是模板扩展有多少代码膨胀。正如他们所做的一切都是演员和&#34; Arg&#34;是一个固定的大小,它的构造函数只加载两个字段,类型和值。请问GCC和MSC能否很好地优化所有这些,因此不存在可变参数模板的完全扩展?

// This is in a "TextWriter" class
template <typename... Args>
int writef(const wchar_t *fmt, ...) {
    FormatfArglist<sizeof...(Args)> arglist;
    FormatfArgBase::addArgs(arglist.args(), args...);
    return(vwritef(fmt, arglist));
}

template <typename First, typename... Rest> 
static void FormatfArgBase::addArgs(Arg *arglist, 
                          const First &first, const Rest &... rest) {            
    setArg(arglist,Arg(first));            
    if(sizeof... (Rest) > 0) {
        addArgs(++arglist, rest...); // recursive call using pack expansion syntax  
    }
}  

答案 1 :(得分:-1)

我不确定为什么它适用于Microsoft编译器。该标准清楚地表明,

  

只有算术,枚举,指针,成员指针和类   允许使用类型参数。

http://en.cppreference.com/w/cpp/language/variadic_arguments)。

对于您的特定情况,我建议您使用可变参数模板函数作为将这些值转换为指针的中间步骤,而不是调用您的Log函数(我认为它不是模板本身)。