Parameters 避免过载解析中的歧义

Parameters 避免过载解析中的歧义,parameters,c++17,ambiguous,Parameters,C++17,Ambiguous,这是问题的后续,所以如果您需要查看Register类,请参考该问题。现在,根据提供的答案,我编写了一个函数来实现这一点。我有两个版本的函数,一个将结果存储回原始版本,另一个将返回副本。以下是我的职能: template<std::uint64_t N> void reverseBitOrder( Register<N>& reg ) { auto str = reg.register_.to_string(); std::reverse(str.b

这是问题的后续,所以如果您需要查看Register类,请参考该问题。现在,根据提供的答案,我编写了一个函数来实现这一点。我有两个版本的函数,一个将结果存储回原始版本,另一个将返回副本。以下是我的职能:

template<std::uint64_t N>
void reverseBitOrder( Register<N>& reg ) {
    auto str = reg.register_.to_string();
    std::reverse(str.begin(), str.end());
    auto x = vpc::Byte(str);
    reg.register_ = x;
}

// Extra unused parameter to avoid ambiguity
template<std::uint64_t N>
Register<N> reverseBitOrder(Register<N>& reg, bool _x_ /*not used*/ ) {
    auto str = reg.register_.to_string();
    std::reverse(str.begin(), str.end());
    auto x = vpc::Byte(str);
    Register<N> temp;
    temp.register_ = x;
    return temp;
}
template<std::uint64_t N> void reverseBitOrder( Register<N>& reg );
template<std::uint64_t N> Register<N> reverseBitOrder( Register<N> const& reg );
第一个保存值,第二个返回副本。我的问题是关于第二个函数,我最后添加了第二个参数,该参数未被使用,以避免由于重载解析而导致的歧义,因为函数不能单独在返回类型上解析。因此,当我调用这个函数时,我必须将0、1、true或false传递给没有效果的函数

总的来说,这本身并不是什么大不了的事,然而,对我来说,它似乎不是很干净和简洁。有没有其他方法来实现这一点?我不想让它成为类的函数。我的寄存器类或结构按原样完成,对寄存器执行的任何类型的操作都将由引用一个或多个寄存器对象的函数完成。

您可以使用来实现这一点

函数模板reverseBitOrder的返回类型应为std::optional

功能模板应修改为:

template<std::uint64_t N>
std::optional<vpc::Register<N>> reverseBitOrder(vpc::Register<N>& reg, bool _x_ = false) {

    auto str = reg.register_.to_string();
    std::reverse(str.begin(), str.end());
    vpc::Register<N> temp;    

    if(_x_) //return copy
    {
        temp.register_ = vpc::Byte(str); //since register_ is a vpc::Byte. Generalize accordingly.
        return temp;
    }
    else //save in the same variable
    {
        reg.register_ = vpc::Byte(str);        
        return {};
    }
}


但是您实际上不需要使用std::optional,因为函数模板中确实没有失败案例

如果我理解正确,两个函数都计算x并将其存储在寄存器中,但一个函数按值返回所述对象,而另一个函数将结果存储在函数的参数reg中

从技术上讲,这可以通过定义以下两个函数对constness进行重载来实现:

template<std::uint64_t N>
void reverseBitOrder( Register<N>& reg ) {
    auto str = reg.register_.to_string();
    std::reverse(str.begin(), str.end());
    auto x = vpc::Byte(str);
    reg.register_ = x;
}

// Extra unused parameter to avoid ambiguity
template<std::uint64_t N>
Register<N> reverseBitOrder(Register<N>& reg, bool _x_ /*not used*/ ) {
    auto str = reg.register_.to_string();
    std::reverse(str.begin(), str.end());
    auto x = vpc::Byte(str);
    Register<N> temp;
    temp.register_ = x;
    return temp;
}
template<std::uint64_t N> void reverseBitOrder( Register<N>& reg );
template<std::uint64_t N> Register<N> reverseBitOrder( Register<N> const& reg );
这样做的问题是,返回值是否被使用并不是可以从函数内部检测到的

让一个函数做两件事的正确方法是让一个函数具有此签名:

template<std::uint64_t N> void reverseBitOrder( Register<N> const& inputReg, Register<N>& outputReg );
现在,如果这真的不能满足您的需要,那么有一种方法可以获得您想要的syntaxic sugar,代价是不必要的复杂性和添加构造函数进行注册。大致如下所示:

// Behaviour 1: value stored in reg
reverseBitOrder(reg, reg);

// Behaviour 2: value stored in val, reg leftuntouched
reverseBitOrder(reg, val);
// Forward declaration
template<std::uint64_t N>
class Register;

// Proxy class
template<std::uint64_t N>
struct RegisterProxy
{
    Register<N>* reg;
    TypeOfX x;

    ~RegisterProxy()
    {
        if (reg)
        {
            reg->register = x;
        }
    }
};

// Modified Register class
template<std::uint64_t N>
class Register
{
    ...

    Register(RegisterProxy& proxy)
    {
        ...
        register = proxy.x;
        proxy.reg = nullptr;
        ...
    }

    ...

    // Define the matching assignment operator too

    ...
};

// Your function
template<std::uint64_t N>
RegisterProxy<N> reverseBitOrder( Register<N>& reg )
{
    auto str = reg.register_.to_string();
    std::reverse(str.begin(), str.end());
    auto x = vpc::Byte(str);
    return RegisterProxy{reg, x};
}

不过,我不建议你这么做,因为这太麻烦了。我建议使用我称之为正确方法的解决方案。它是最简单的,也是最难在以后使用的

你真的需要两个功能吗?为什么不同时使用返回副本的函数呢?如果需要,您可以将返回值赋给原始变量。@P.W True,但我试图保持函数的名称不变,因为它做的是相同的事情唯一的区别是;我确实需要两个不同的函数,一个用于覆盖该值,另一个用于保留并返回新值的副本。@P.W我想我可以使用bool参数,并将其默认为false,然后执行覆盖操作,但如果为copy传递了true,则会分支到另一个节,我尝试了上面的实现,但在返回复制的值时,我被迫使用auto。我宁愿将它存储到另一个寄存器的实例中。所以我选择做你在这里做的事,但是没有std::optional。我的返回类型只是一个寄存器。工作起来很有魅力!我曾想过将代码分支到单个函数中。。。但也倾向于使用单独的函数…这对寄存器(默认大小)很有效,但当我尝试将其用于更大的寄存器时,它失败了,因为reg.Register\u=Bytestr…@FrancisCugler:请参阅if子句中赋值语句后的注释。您已经在寄存器结构中将寄存器定义为vpc::Byte。我很感激你的努力,这里有一些好的建议,但是我正在努力保持注册的可复制性;所以我需要它的默认构造函数,复制构造函数,等等都是默认的。是的,正如我所说的,使用代理和所有这些都是非常麻烦的。正确的方法是使用inputReg和outputRegI对我的答案进行了一些修改,使我的建议更加清晰