操作员过载无效



我的代码中有一个案例,我想通过模板调用类定义的二进制运算符重载,但第二个参数可能是类型void。有可能写那个专业吗?

原因:

因此,我有一块现有的宏化/模板包装,它可以帮助我记录函数的返回值。

它有点像这样:

#define Return  return DebugPlacement({__FILE__,__LINE__}) <<= 

其中DebugPlacement是一个小的spot类,它具有operator <<=的模板重载

struct DebugPlacement
{
const char* path; int line;
template <class Arg>
const Arg& operator <<= (const Arg& arg)const
{
std::cerr << "DIAG: " << path << ":" << line << " returns " << arg << std::endl;
return arg;
}
};

我们选择了运算符<lt;=因为它相当模糊,行为有点像现有的流媒体运营商,但恰恰相反。此外,它的低优先级意味着几乎任何合理的表达式都可以写在RHS上。

另一个折衷方案是:所有类型通常都很简单,所以rval的使用不是什么大问题。我相信我们最终会看到这里需要完美的转发,但现在还没有。

它打印值并返回。我可以根据需要插入各种通用专业,-char*等。不需要额外的括号。它工作得很好,谢谢你的询问!

在许多情况下,它被用于API存根:

extern int MyFunction(int (arg1), int (arg2));
int MyFunctionStub(int (arg1), int (arg2))
{
Return MyFunction(int (arg1), int (arg2));
}

而这种存根行为,反过来又以宏观化告终。我知道——这是一种诅咒,也是一种祝福。不用说,我们的用例并不是那么琐碎。存根也有工作要做,所以不能删除或模板化。存根的名称在历史上也被固定为"公共";C";API

但如果返回类型为void,则一切都会分崩离析!

看起来不错的c++之神认为以下内容是可以接受的,可能是因为模板包装器需要盲目转发返回类型:

extern void MyVFunction(int (arg1), int (arg2));
void MyVFunctionStub(int (arg1), int (arg2))
{
return MyVFunction(int (arg1), int (arg2));
}

但是使用宏替换,我无法添加跟踪。他们不喜欢:

extern void MyVFunction(int (arg1), int (arg2));
void MyVFunctionStub(int (arg1), int (arg2))
{
return DebugPlacement({__FILE__,__LINE__}) <<= MyVFunction(int (arg1), int (arg2));
}
Errors (at the call-site):
error: no viable overloaded '<<='
note: candidate template ignored: substitution failure [with T = void]: cannot form a reference to 'void'

那么,是否有某种形式的单词来声明二元运算符的专业化,它确实需要右手边,但类型为void?目前,我们仍然生活在c++11的土地上。我是要等待稍后的c++标准,还是标准化之神这次不看好我?

当然,我尝试过一些东西:

template <>
auto DebugPlacement::operator <<=(void& t)const -> void&
error: cannot form a reference to 'void'

还有

void operator <<=(void t)const 
error: argument may not have 'void' type

我的代码中有一个案例,我想通过模板调用类定义的二进制运算符重载,但第二个参数可能是类型void。有可能写那个专业吗?

您可以使用内置的二进制逗号运算符处理void返回类型

在逗号表达式E1, E2中,表达式E1被求值,其结果被丢弃(尽管如果它具有类类型,则直到包含完整表达式的末尾才会被销毁(,并且其副作用在表达式E2的评估开始之前完成(注意,用户定义的运算符不能保证排序((直到C++17(

当其右侧操作数为void时,逗号运算符的计算结果为void。逗号运算符只能为非空操作数重载。当任何操作数为void时,只调用内置逗号运算符,不考虑用户定义的operator,

逗号运算符优先级最低,非常适合您的任务。

注意逗号符号(,(在不同的上下文中有不同的含义:

各种逗号分隔列表中的逗号,如函数参数列表(f(a, b, c)(和初始值设定项列表int a[] = {1, 2, 3},不是逗号运算符。如果逗号运算符需要在此类上下文中使用,则必须将其加括号:f(a, (n++, n + b), c)

C++11示例:

#include <iostream>
#include <utility>
struct ReturnValueLogger {
char const* file_;
int const line_;
std::ostream& log_file_line() const {
return std::clog << file_ << ":" << line_ << ' ';
}
ReturnValueLogger(ReturnValueLogger const&) = delete;
~ReturnValueLogger() {
if(file_) // operator, overload is not called for void rhs.
log_file_line() << "Return value is voidn";
}
template<class T>
auto operator,(T&& rhs) -> decltype(std::forward<T>(rhs)) { // Not called for void rhs.
log_file_line() << "Return value is " << rhs << 'n';
file_ = 0;
return std::forward<T>(rhs);
}
};
#define Return return ReturnValueLogger{__FILE__,__LINE__},
int  f() { return 1; }
void g() {}
int  f2() { Return f(); } // Outputs "Return value is 1".
void g2() { Return g(); } // Outputs "Return value is void".
int main() {
f2();
g2();
}

重载逗号运算符对于类似的宏Throw也很有用,可以在throw站点检测具有堆栈跟踪、文件和行信息的异常。

最新更新