Если я правильно понимаю, обе функции вычисляют x
и сохраняют его в Register<N>
, но одна возвращает указанный объект по значению, а другая сохраняет результат в аргументе функции reg
.
Технически , это может быть сделано путем перегрузки константности путем определения этих двух функций:
template<std::uint64_t N> void reverseBitOrder( Register<N>& reg );
template<std::uint64_t N> Register<N> reverseBitOrder( Register<N> const& reg );
Хотя это технически отвечает на ваш вопрос, это было бы ужасно.Если я не ошибаюсь, реальная проблема в том, что вам нужно следующее:
// Behaviour 1: value stored in reg
reverseBitOrder(reg);
// Behaviour 2: value stored in val, reg left untouched
auto val = reverseBitOrder(reg);
Проблема в том, что используется возвращаемое значение или нет - это не то, что вы можете обнаружить изнутриfunction.
Правильный способ сделать так, чтобы одна функция делала две вещи, состоял бы в том, чтобы иметь функцию с такой сигнатурой:
template<std::uint64_t N> void reverseBitOrder( Register<N> const& inputReg, Register<N>& outputReg );
Эта функция будетиспользуйте inputReg
для вычисления x
, затем сохраните результат в outputReg
, то есть вы бы использовали его следующим образом:
// Behaviour 1: value stored in reg
reverseBitOrder(reg, reg);
// Behaviour 2: value stored in val, reg leftuntouched
reverseBitOrder(reg, val);
Теперь, если это действительно нене делайте этого за вас, есть способ получить синтаксический сахар , который вы ищете, за счет ненужной сложности и добавления конструктора к Register<N>
.Это выглядело бы примерно так:
// 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};
}
Это позволяет вам делать
// Behaviour 1: temporary object immediately destroyed and value stored in reg
reverseBitOrder(reg);
// Behaviour 2: constructor called, value stored in val
// the temporary object's destructor doesn't do anything, reg left untouched
auto val = reverseBitOrder(reg);
Хотя я не могу рекомендовать это делать, это больше проблем, чем стоит.Я предлагаю использовать решение, которое я назвал «правильный путь».Это наименее сложный и тот, который труднее всего использовать неправильно позже