我正在尝试在 C++ 中添加调试工具。我想探测变量的所有更改。为此,我使用 c++20std::source_location::current()功能,如以下成员函数:
void DoubleWithProbe::set(double newValue, std::source_location loc = std::source_location::current())
{
std::cout << "Changed: new = " << newValue << ", old = " << m_value
<< " (" << loc.file_name() << ":"
<< loc.line() << ")" << std::endl;
m_value = newValue;
}
Run Code Online (Sandbox Code Playgroud)
然而,这需要调用者使用设置函数。如果我尝试使用运算符,该模式将失败:
operator double(std::source_location loc = std::source_location::current()) const
{
std::cout << "Accessed: value = " << m_value <<
<< " (" << loc.file_name() << ":"
<< loc.line() << ")" << std::endl;
return m_value;
}
DoubleWithProbe& operator=(double newValue, std::source_location loc = std::source_location::current())
{
...
}
Run Code Online (Sandbox Code Playgroud)
它们都是非法的,因为operator double可能没有参数并且operator=必须只有一个参数。对于operator=,我找到了这个解决方法:
struct DoubleAndLoc
{
double m_val;
std::source_location m_loc;
// not explicit.
DoubleAndLoc(double val, std::source_location loc = std::source_location::current())
: m_val(val), m_loc(loc)
{
}
};
DoubleWithProbe& operator=(DoubleAndLoc newValue)
{
...
}
Run Code Online (Sandbox Code Playgroud)
对于双精度数来说这可能没问题,但是对于字符串来说,这很快就会遇到双精度转换问题。
有什么办法可以让operator double()工作变得operator=()更干净?
一个有效的示例位于https://godbolt.org/z/4Ea1sPT1n。
该答案的先前版本使用推论来声明转换函数,如下所示:
template <typename T>
struct RefWithLoc {
T& t;
std::source_location loc;
RefWithLoc(T& t, std::source_location loc = std::source_location::currenct())
: t(t)
, loc(loc)
{ }
};
struct DoubleWithProbe {
operator double(this RefWithLoc<DoubleWithProbe const> self);
};
Run Code Online (Sandbox Code Playgroud)
然而,这……行不通。[over.best.ics.general]/4禁止为用户定义的转换函数的对象参数考虑用户定义的转换序列(原则上最多允许发生一次转换)。
有了上面的内容,你仍然可以写dwp.operator double(),但不行static_cast<double>(dwp)。
也许您可以轻松地使其与命名转换一起使用(即使在c++20中)这一事实表明,如果需要该功能,那么您可以只添加一个to_double()函数吗?
您可以概括您的DoubleAndLoc,然后使用成员函数重载而不是operator =。
template <typename T>
struct LocatedValue
{
T m_val;
std::source_location m_loc;
// not explicit.
LocatedValue(T val, std::source_location loc = std::source_location::current())
: m_val(std::forward<T>(val)), m_loc(loc)
{
}
};
class StringWithProbe {
public:
StringWithProbe& operator=(LocatedValue<const char *> newValue)
{
assign(newValue.m_val, newValue.m_loc);
return *this;
}
StringWithProbe& operator=(LocatedValue<std::string> newValue)
{
assign(newValue.m_val, newValue.m_loc);
return *this;
}
private:
void assign(const char * value, std::source_location loc)
{
//...
}
void assign(std::string value, std::source_location loc)
{
//...
}
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
611 次 |
| 最近记录: |