Reputation: 22173
I have the following class in c++11:
#include <iostream>
#include <string>
#include <utility>
void overloaded_function(const std::string& param) {
someStuffHere
}
void overloaded_function(std::string&& param) {
someStuffHere
}
As you can see the overloaded_function implementation is exactly the same. I would like to create a new function instead of having the same implementation into two different methods. I tried with:
void overloaded_function(const std::string& param) {
uniqueCall(std::forward<std::string&>(param));
}
void overloaded_function(std::string&& param) {
uniqueCall(std::forward<std::string&&>(param));
}
void uniqueCall(T&& param) {
someStuffHere
}
but it doesn't work due to the lvalue reference not accepted by uniqueCall.
Upvotes: 8
Views: 615
Reputation: 45654
I suggest delegating directly to a template function:
void overloaded_function(const std::string& param) {
uniqueCall(param);
}
void overloaded_function(std::string&& param) {
uniqueCall(std::move(param));
}
template <class T>
void uniqueCall(T&& param) {
someStuffHere
}
If you identify some substantial enough amount off work not benefitting from treating param
as anything but a const std::string&
, it might make sense for executable-size or organization to promote it to its own function. Maybe it makes sense to treat it as a C++17 std::string_view
for that?
That template-function you delegate to, or the helper-function you call from it, might even be some interesting and valuable addition to your interface, maybe after a minor adjustment, see .emplace_@()
and .put_@()
in the standard-library containers.
Upvotes: 1
Reputation: 24402
Once r-value parameter gets a name - it can be treated, this named parameter, as l-value reference, as you can read in http://en.cppreference.com/w/cpp/language/value_category:
Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;
So you might write as simple as this:
void overloaded_function(std::string& param) {
someStuffHere
}
void overloaded_function(std::string&& param) {
overloaded_function(param); // here param type is std::string&
}
If you really enjoy to have "common" function - it shall accept lvalue ref for the very same reasons:
void uniqueCall(std::string& param) {
some stuff here
}
void overloaded_function(std::string& param) {
uniqueCall(param)
}
void overloaded_function(std::string&& param) {
uniqueCall(param); // here param type is std::string&
}
Upvotes: 5
Reputation: 69882
A common pattern is to have the argument type of the interface function deduced:
template<class Param>
void overloaded_function(Param&& param)
{
commonStuff(param);
mutabilityDependentStuff(std::forward<Param>(param));
}
Regardless of whether Param is an r-value or l-value reference, it can decay into a const l-value reference:
void commonStuff(std::string const& arg)
{
//
}
And std::forward<>
can use used to detect proper decay into mutable and immutable versions (mutable r-values will decay to mutable l-values):
void mutabilityDependentStuff(std::string const& arg)
{
//
}
void mutabilityDependentStuff(std::string& arg)
{
//
}
Upvotes: 1
Reputation: 170074
If you don't need to modify the argument, you don't need an rvalue overload at all1. A const lvalue reference will happily bind to an rvalue.
That's how C++ always worked, and rvalue references don't change that.
So a simple
void overloaded_function(const std::string& param) {
//someStuffHere
}
Will bind to an argument of whatever value category.
1 - And if you did need to modify it, then passing rvalues is a bit dubious.
Upvotes: 7