我有一些调试代码如下所示:
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define AT __FILE__ ":" TOSTRING(__LINE__)
void __my_error(const char*loc, const char *fmt, ...);
#define my_error(fmt, ...) __my_error(AT, fmt, ##__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)
使用最后一个宏,因此我可以将位置插入到调试输出中,以确定错误发生的位置.但是,当我调用这样的函数时:
my_error("Uh oh!");
Run Code Online (Sandbox Code Playgroud)
我喜欢我的代码是C99,所以我觉得这个时候编译,我得到以下错误:
error: ISO C99 requires rest arguments to be used
Run Code Online (Sandbox Code Playgroud)
我知道我可以通过改变呼叫来解决这个问题
my_error("Uh oh!", NULL);
Run Code Online (Sandbox Code Playgroud)
但有什么方法可以让这个看起来不那么难看?谢谢!
我正在研究一个事件库,我遇到了Variadic模板的问题.
一切都工作得非常好,除了我不能将参考作为参数传递...
这是一个非常简化的例子,用来揭露我的问题.
struct DelayedSignal
{
~DelayedSignal ()
{ std::cout << "~DelayedSignal CLOSE" << std::endl; }
template<class C, class... Args>
DelayedSignal ( void(C::*func)(Args...), C& obj )
{ std::cout << "DelayedSignal INIT - 03 - pointer to method & pointer to class instance (Arg num: " << sizeof...(Args) << ")" << std::endl; }
template<class C, class... Args>
DelayedSignal ( void(C::*func)(Args...), C& obj, Args... args )
{
std::cout << "DelayedSignal INIT - 04 - pointer to method & pointer to class instance …Run Code Online (Sandbox Code Playgroud) 我正在尝试为不同的函数实现一个容器类,我可以在其中保存函数指针并使用它来稍后调用这些函数.我会尝试更准确地描述我的问题.
例如,我有两种不同的测试功能:
int func1(int a, int b) {
printf("func1 works! %i %i\n", a, b);
return 0;
}
void func2(double a, double b) {
printf("func2 works! %.2lf %.2lf\n", a, b);
}
Run Code Online (Sandbox Code Playgroud)
我还有一系列变体,它们包含函数参数:
std::vector<boost::variant<int, double>> args = {2.2, 3.3};
Run Code Online (Sandbox Code Playgroud)
我已经决定使用从某个基类派生的我自己的仿函数类(我考虑过使用虚方法):
class BaseFunc {
public:
BaseFunc() {}
~BaseFunc() {}
};
template <typename T>
class Func;
template <typename R, typename... Tn>
class Func<R(Tn...)> : public BaseFunc {
typedef R(*fptr_t)(Tn...);
fptr_t fptr;
public:
Func() : fptr(nullptr) {}
Func(fptr_t f) : fptr(f) {}
R operator()(Tn... args) …Run Code Online (Sandbox Code Playgroud) 我有一些代码在GCC下工作,但无法在Visual Studio 2015下编译(我意识到它正在开发中,但我认为应该实现这个领域).
template< typename... T >
class inherit : public T...
{
public:
inherit(T... t) : T(t)... {}
};
int main() {
auto l1 = []() {};
auto l2 = []() {};
inherit<decltype(l1), decltype(l2)> test(l1, l2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是代码片段简化为它的纯粹本质.Visual Studio在继承的构造函数上说"语法错误:'type'".然后它会稍微探讨它是如何到达那里的,并以"你不能构建一个lambda实例"结束.
我的假设是T(t)的扩展......没有正确扩展.但是我可能会错误地使用语法.
编辑:对不起,问题是:我在这里有错吗?如果是这样,那么正确的语法是什么?
其他发现:为了与我所拥有的回复保持一致,这似乎是Visual Studio 2015在此领域存在错误的问题.在测试中,它似乎是扩展,其中构造函数params被传递给具有问题的lambda基类.以下测试在VS2015下运行:
template< typename T1, typename T2, typename... T3 >
class inherit2 : public T3...
{
public:
inherit2(T1 t1, T2 t2) : T1(t1), T2(t2) {}
};
int main() {
auto l1 = []() …Run Code Online (Sandbox Code Playgroud) 我创建了一个具有可变参数模板方法的类.这个方法调用printf函数.将零参数传递给方法时,我得到gcc的编译警告说:
警告:格式不是字符串文字而没有格式参数[-Wformat-security]
一个简化的类示例是:
class printer{
std::map<int,std::string> str;
public:
printer(){
str[0] = "null\n";
str[1] = "%4d\n";
str[2] = "%4d %4d\n";
str[3] = "%4d %4d\n%4d\n";
}
template<typename ...Args>
void print(Args... args){
printf(str[sizeof...(args)].c_str(),args...);
}
};
Run Code Online (Sandbox Code Playgroud)
使用时
printer p;
p.print(23);
p.print(345,23);
Run Code Online (Sandbox Code Playgroud)
一切顺利,但使用时
printer p;
p.print();
Run Code Online (Sandbox Code Playgroud)
我收到编译警告
main.cpp: In instantiation of ‘void printer::print(Args ...) [with Args = {}]’:
main.cpp:23:11: required from here
main.cpp:17:50: warning: format not a string literal and no format arguments [-Wformat-security]
printf(str[sizeof...(args)].c_str(),args...);
Run Code Online (Sandbox Code Playgroud)
当然,如果我只是打电话
printf("null\n");
Run Code Online (Sandbox Code Playgroud)
没有警告出现.
有人可以解释为什么会这样吗?
我可以在不禁用-Wformat-security标志的情况下删除警告吗?
考虑这个输出:
int foo (int, char) {std::cout << "foo\n"; return 0;}
double bar (bool, double, long ) {std::cout << "bar\n"; return 3.5;}
bool baz (char, short, float) {std::cout << "baz\n"; return true;}
int main() {
const auto tuple = std::make_tuple(5, 'a', true, 3.5, 1000, 't', 2, 5.8);
multiFunction<2,3,3> (tuple, foo, bar, baz); // foo bar baz
}
Run Code Online (Sandbox Code Playgroud)
因此,multiFunction<2,3,3>获取前2个元素tuple并将它们传递给foo接下来的3个元素tuple并将它们传递给bar等等...我得到了这个工作(除非函数有重载,这是一个单独的问题).但是所调用的每个函数的返回值都会丢失.我希望将这些返回值存储在某处,例如
std::tuple<int, double, bool> result = multiFunction<2,3,3> (tuple, foo, bar, baz);
Run Code Online (Sandbox Code Playgroud)
但我不知道如何实现这一点.对于那些想要帮助完成这项工作的人来说,这是我目前为止的(更新的)工作代码,它仅将输出存储到字符串流中.不容易获得所有值,特别是如果流中保存的对象是复杂类.
#include <iostream> …Run Code Online (Sandbox Code Playgroud) 我有以下内容:
template<typename FIRST, typename SECOND>
Sender *createSenderChain() {
return new FIRST(new SECOND());
}
Run Code Online (Sandbox Code Playgroud)
是否可以使模板可变:
template<typename FIRST, typename ...Args>
Sender *createSenderChain() {
return new FIRST(new SECOND(new THIRD(new ...)) <-- This is the pattern I want,
but how should it be done
using the args list?
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试为Swift 4/iOS 11中的os_log编写一个方便的包装器,但是我已经遇到了传递可变参数的艰难战斗.
基本上,我想编写一个如下所示的函数.
static let logger = OSLog(subsystem: "com.example.foo", category: "foobar")
func logError(_ message: StaticString, _ args: Any...) {
os_log(message, log: logger, type: .error, args)
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,我似乎无法弄清楚传递参数的神奇语法,并且在CVarArg讨论的泥潭中有点迷失.
(...这让我想念Python的splatting语法)
我正在尝试创建一个函数,该函数可以采用相同类型的多个参数,并作为模板传入。参数的数量在编译时是已知的:
struct Foo
{
int a, b, c;
};
template <uint32_t argsCount, typename T>
void fun(T ...args) // max number of args == argsCount
{
// ...
// std::array<T, argsCount>{ args... };
}
int main()
{
fun<3, Foo>( { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } );
// Dont want to do:
// fun( Foo{}, Foo{}, Foo{} );
// nor:
// fun<Foo, Foo, Foo>( ... );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我必须考虑这些限制: