c++ std::source_location 可以与转换运算符一起使用吗?

Rob*_*b L 8 c++ c++20

我正在尝试在 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

Bar*_*rry 9

中,没有。但在中...仍然没有。


该答案的先前版本使用推论来声明转换函数,如下所示:

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)

也许您可以轻松地使其与命名转换一起使用(即使在中)这一事实表明,如果需要该功能,那么您可以只添加一个to_double()函数吗?


Cal*_*eth 1

您可以概括您的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)

在 coliru 上查看