Search code examples
parametersc++17ambiguous

Avoiding ambiguity in overload resolution


This is a follow up to this question so if you need to see the Register class please refer to that question. Now based on the supplied answer I have written a function to do just that. I have 2 versions of the function one that will store the results back into the original and one that will return a copy. Here are my functions:

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;
}

The first one saves the value, the second returns a copy. My question is on the 2nd function I ended up adding a second parameter that is not used in order to avoid ambiguity due to overload resolution as functions can not be resolved on return types alone. So when I call this function I would have to pass either 0, 1, true or false to the function which has no effect.

Overall this in itself is not a very big deal, however, it doesn't seem very clean and concise to me. Are there any other ways to achieve this? I prefer not to make this a function of the class. My Register class or struct is complete as is and any kind of operations done on a register will be done by functions that take a reference to one or more register objects.


Solution

  • You can use std::optional to achieve this.

    The return type of function template reverseBitOrder should be std::optional<vpc::Register<N>>.

    The function template should be modified to:

    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 {};
        }
    }
    

    Live Demo here.

    But you don't really need to use std::optional, since there is really no "failure" case in the function template.