Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;11 lambda作为std::function params传递-返回类型上的分派_C++_Templates_Lambda_C++11_Std Function - Fatal编程技术网

C++ C++;11 lambda作为std::function params传递-返回类型上的分派

C++ C++;11 lambda作为std::function params传递-返回类型上的分派,c++,templates,lambda,c++11,std-function,C++,Templates,Lambda,C++11,Std Function,情景: 我们有一个具有通用错误处理接口的API。这是一个C API,因此它告诉我们,在调用每个API函数之后,我们需要执行如下的样板文件: if (APIerrorHappened()) { APIHandle h; while(h = APIgetNextErrorContext(...)) { cerr << APIgetText(h) << endl; } } ... // this API call returns some

情景:

我们有一个具有通用错误处理接口的API。这是一个C API,因此它告诉我们,在调用每个API函数之后,我们需要执行如下的样板文件:

if (APIerrorHappened()) {
    APIHandle h;
    while(h = APIgetNextErrorContext(...)) {
       cerr << APIgetText(h) << endl;
    }
}
...
// this API call returns something
APItype foo = MYMACRO(APIsomeFunction1(...));
// this one doesn't
MYMACRO(APIsomeFunction2(...));
// neither does this (glCompileShader)
MYMACRO(APIsomeFunction3(...));
...
您也可以从面向方面编程的角度来考虑这一点-想象一下宏添加日志记录,将信息发送到远程监视器,等等。。。关键是它应该封装一个表达式,在它周围执行任何操作,并返回表达式返回的任何类型-当然,表达式可能不会返回任何内容

这意味着你不能只做

#define MYMACRO(x) { auto x = expr(); ... }
…因为在某些情况下,表达式不会返回任何内容

所以。。。你会怎么做

请不要建议将完整语句封装在宏中

#define MYMACRO(x)       \
{                        \
   /* ... stuff ...   */ \
   x;                    \
   // ... stuff
}
…因为这对以下情况不起作用:

if (foo() || APIfunctionReturningBool(...) || bar()) {
     ...
     APIfunction1();
     ...
} else if (APIOtherfunctionReturningBool() || baz()) {
     ...
     APIfunction2();
     ...
}
…你吞没了所有的if语句?它的操作包括其他API调用,因此。。。宏中的宏?调试成了地狱

下面是我自己的尝试,使用lambdas和std::function-但可以说,它是丑陋的。。。 我无法将表达式的lambda直接传递给使用std::function(根据lambda的返回类型进行专门化)的模板,因此代码结果相当糟糕

你能想出更好的办法吗

void commonCode(const char *file, size_t lineno) {
    // ... error handling boilerplate
    // ... that reports file and lineno of error
}

template <class T>
auto MyAPIError(std::function<T()>&& t, const char *file, size_t lineno) -> decltype(t()) {
    auto ret = t();
    commonCode(file,lineno);
    return ret;
}

template<>
void MyAPIError(std::function<void(void)>&& t, const char *file, size_t lineno) {
    t();
    commonCode(file,lineno);
}

template <class T>
auto helper (T&& t) -> std::function<decltype(t())()>
{
    std::function<decltype(t())()> tmp = t;
    return tmp;
}

#define APIERROR( expr ) \
    return MyAPIError( helper( [&]() { return expr; } ),  __FILE__, __LINE__);
这种形式的宏保证了实际的C API(通过VA_ARGS调用)永远不会抛出-因此,ErrorChecker的析构函数中的“抛出”将始终是执行此操作的第一个析构函数


因此,这个解决方案涵盖了我最初问题的所有角度-非常感谢您提供了它。

将日志代码放在某个类的析构函数中-假设记录器不会抛出-然后在宏中创建该类的实例。滥用逗号运算符,我们有:

struct Logger
{
    const char* file;
    int lineno;
    ~Logger()
    {
        // The APIerrorHappened stuff.
    }
};

#define APIERROR(...) (Logger{__FILE__, __LINE__}, (__VA_ARGS__))

演示:

看到您已经对它发表了评论,但是如果错误处理程序抛出该怎么办?我们不能从Logger的析构函数中抛出任何关于如何处理这个问题的想法?@ttsiodras:您可以传递
Logger
的构造函数一个回调,该回调应该在异常情况下调用;析构函数将在try/catch内部调用该函数。当然,该回调也不例外。@ttsiodras:当
commonCode
抛出时,代码可以工作(但当
expr
抛出时,代码不能工作)。你能不能把那
commonCode
noexcept
?@KennyTM:鉴于commonCode正在进行错误处理,它在stderr中报告错误,然后抛出异常是很正常的。。。以下是我的想法(OpenGL的东西)
#define GLERROR(...)                                    \
    ([&]() -> decltype(__VA_ARGS__)                     \
    {                                                   \
        ErrorChecker _api_checker {__FILE__, __LINE__}; \
        (void) _api_checker;                            \
        try {                                           \
            return __VA_ARGS__;                         \
        } catch(...) {}                                 \
    } ())
struct Logger
{
    const char* file;
    int lineno;
    ~Logger()
    {
        // The APIerrorHappened stuff.
    }
};

#define APIERROR(...) (Logger{__FILE__, __LINE__}, (__VA_ARGS__))