There are 2 function overloads:
MyClass do_something(MyClass param);
const MyClass& do_something(const MyClass& param);
Then I do:
MyClass c1 {"c1"};
do_something(c1); // I want this to be used by value overload
do_something(c1); // this to be used by reference overload
Is there any special way to explicitly specify that argument is passed by value or by reference?
For move semantic there is std::move() I wonder if there is anything like std::copy() std::ref for my case?
P.S. It's not to be used in real program, just checking out by myself the difference of passing arguments, returning values and their behaviour in different ways and have all functions with the same name:
// pass by value (copy)
MyClass do_something(MyClass param) {
cout << "do_something(MyClass param)" << endl;
param.i = 100;
return param;
}
// !!! Your normal habit when passing an argument to a function should be to pass by const reference. (thinking in c++)
// pass by reference (reference)
const MyClass& do_something(const MyClass& param) { // doesn't allow to modify the object
cout << "do_something(MyClass& param)" << endl;
return param;
}
// pass by move semantic (move)
MyClass&& do_something(MyClass&& param) {
cout << "do_something(MyClass&& param)" << endl;
param.name += "__after_do_something(MyClass&& param)";
param.i = 100;
return move(param);
}
// pass by pointer (reference)
MyClass* do_something(MyClass* const param) { // allows to modify object, but not pointer (address)
cout << "do_something(MyClass* const param)" << endl;
param->i = 100;
// (*param).i = 100; // the same as above
return param;
}
You can resolve an overload ambiguity by casting to the relevant function pointer type (it's one of the rare cases where the type of an expression is determined by outer context, instead of being built up from inside):
struct MyClass { char const* s; };
MyClass do_something(MyClass) { return MyClass(); }
const MyClass& do_something(const MyClass& param) { return param; }
auto main() -> int
{
MyClass c1 {"c1"};
static_cast<MyClass(*)(MyClass)>( do_something )( c1 ); // Value overload
static_cast<MyClass const&(*)(MyClass const&)>( do_something )( c1 ); // Ref overload
}
But in practice you should just name the functions differently, or use tie-breaker arguments or argument types, i.e., designing the functions for explicit choice of function.
I would name them differently because they do different things, so it indicates the Wrong Thing™ to have the same name for them.
Is there any special way to explicitly specify that argument is passed by value or by reference?
No, but there are workaround.
With template method and specialization, you may explicitly tell which version you want:
template <typename T>
T do_something(T);
template<>
MyClass do_something(MyClass) { std::cout << "value" << std::endl; }
template<>
const MyClass& do_something(const MyClass&)
{
std::cout << "reference" << std::endl;
}
And then call it:
do_something<MyClass>(c); // value
do_something<const MyClass&>(c); // reference
do_something(c); // value
Live Demo
But it would be simpler/cleaner to create overload with explicit tag:
struct by_value{};
struct by_ref{};
MyClass do_something(MyClass, by_value) { std::cout << "value" << std::endl; }
const MyClass& do_something(const MyClass&, by_ref)
{
std::cout << "reference" << std::endl;
}
And call it
do_something(c, by_value{}); // value
do_something(c, by_ref{}); // reference
Is there any special way to explicitly specify that argument is passed by value or by reference?
Yes. If it is not copyable (i.e., deleted or private copy constructor) it can only be passed by reference.
Related
Currently, I'm storing a collection of std::unique_ptrs to heap allocated objects of a polymorphic type:
struct Foo {
virtual ~Foo() = default;
};
Collection<std::unique_ptr<Foo>> foos;
The basic interface I need is putting / taking owners of Foo to / from foos. The objects stored in foos are never supposed to be nullptr so I'd like to replace runtime assert(owner_taken) with compile-time checks. Moreover, I would like to be capable of using non-null owners in the context where a nullable one may be expected.
Probably, I need to store something like unique_ref but how would I extract one from foos? I don't want a copy, I want the stored object itself, so owner->clone() isn't a solution. Neither I can std::move(owner) because the state of a "unique reference" would be invalid afterwards.
Is there a clean design decision?
Is there a never-null unique owner of heap allocated objects?
There is no such type in the standard library.
It is possible to implement such type. Simply define a type with unique_ptr member and mark the default constructor deleted. You can mark constructor from std::nullptr_t deleted also so that construction from nullptr will be prevented at compile time.
Whether you construct from an external pointer, or allocate in the constructor, there is no alternative for checking for null at runtime.
Reading your question, I interpret the following requirements:
You don't want to copy or move the object itself (Foo)
You don't want a wrapper which has some sort of empty state which excludes move semantics
The object itself (Foo) should be stored on the heap such that its lifetime is independent of the control flow
The object itself (Foo) should be deleted once it is not used any more
As construction / destruction, copy and move are the only ways to get objects into / out of a container, the only thing left is a wrapper object which is copied when moved into / out of the container.
You can create such an object yourself as follows:
// LICENSE: MIT
#include <memory>
#include <utility>
template<typename T>
class shared_ref {
public:
template<typename ...Args>
shared_ref(Args&&... args)
: data{new T(std::forward<Args>(args)...)}
{}
shared_ref(shared_ref&&) = delete;
shared_ref& operator=(shared_ref&&) = delete;
T& get() noexcept {
return *data;
}
const T& get() const noexcept {
return *data;
}
operator T&() noexcept {
return get();
}
operator const T&() const noexcept {
return get();
}
void swap(shared_ref& other) noexcept {
return data.swap(other);
}
private:
std::shared_ptr<T> data;
};
template<class T>
void swap(shared_ref<T>& lhs, shared_ref<T>& rhs) noexcept {
return lhs.swap(rhs);
}
I leave it as an exercise to the reader to add support for Allocator, Deleter, operator[], implicit conversion contructor to base classes.
This can then be used as follows:
#include <iostream>
int main() {
shared_ref<int> r; // default initialized
std::cout << "r=" << r << std::endl;
r = 5; // type conversion operator to reference
std::cout << "r=" << r << std::endl;
shared_ref<int> s{7}; // initialized with forwarded arguments
std::cout << "s=" << s << std::endl;
std::swap(r, s);
std::cout << "r=" << r << ", " << "s=" << s << std::endl;
s = r; // copy assignment operator
std::cout << "s=" << s << std::endl;
const shared_ref<int> t{s}; // copy constructor
std::cout << "t=" << t << std::endl;
//t = 8; // const ref from a const object is immutable
return 0;
}
Here is some class with two overloaded methods foo:
class Object {
public:
Object (double someVal) : val(someVal) { }
double getter () const { return val; }
double& getter () { return val; }
private:
double val;
};
So now the double Object::getter() const function will be called on const instances
const Object instance(42);
cout << instance.getter() << endl; // called: `double getter() const`
Now, I am trying to get reference to double getter() const function and assign it to std::function type
const Object instance(42);
function<double(const Object&)> foo = &Object::getter;
cout << foo(instance) << endl;
The code works fine if function double& getter() is removed, but with it I got the following error on the second line:
test.cpp:18:34: error: no viable conversion from '<overloaded function type>' to
'function<double (const Object &)>'
function<double(const Object&)> foo = &Object::getter;
^ ~~~~~~~~~~~~~~~
It seems that error happens, because system tries to call double& getter().
The question is how to force calling of double getter() const?
The full listing is attached here
By casting to the specific function pointer type:
std::function<double(const Object&)> foo = static_cast<double(Object::*)() const>(&Object::getter);
Just use a lambda closure:
Object o{0.0};
std::function<double()> f = [o](){ return o.getter(); };
The lambda calls the const version of getter(), as captured variables are const by default (otherwise you'd have to use mutable).
Address of Overload functions defined 7 contexts where the correct overload can be deduced. Yet std::function<...> is not one of them. Thus, the overload function to get address of is ambiguous.
There are a few ways to select the overload you want:
const Object instance(42);
// Use static_cast to select overload
std::function<double(const Object&)> foo = static_cast<double(Object::*)() const>(&Object::getter);
// Use lambda to select overload
// std::function type parameters can be omitted since c++ 17
// Guaranteed copy elision since c++ 17
std::function bar = [](const Object& instance) { return instance.getter(); };
// Use std::mem_fn
std::function<double(const Object&)> mfn = std::mem_fn<double() const>(&Object::getter);
However, an idiomatic way to declare methods with similar functionality but differed by constness is actually to declare two different functions: foo() and cfoo(). Think about begin() and cbegin(). The latter returns a const iterator.
You can use a typedef to disambiguate the function you want:
#include <iostream>
#include <functional>
class Object {
public:
Object (double someVal) : val(someVal) { }
double getter () const { return val; }
double& getter () { return val; }
private:
double val;
};
typedef double (Object::*funtype)() const;
int main()
{
const Object instance(42);
std::function<double(const Object&)> foo = static_cast<funtype>(&Object::getter);
std::cout << foo(instance) << std::endl;
}
run on cpp.sh
Or, without casting:
#include <iostream>
#include <functional>
class Object {
public:
Object (double someVal) : val(someVal) { }
double getter () const { return val; }
double& getter () { return val; }
private:
double val;
};
typedef double (Object::*funtype)() const;
int main()
{
const Object instance(42);
funtype temp = &Object::getter;
std::function<double(const Object&)> foo = temp;
std::cout << foo(instance) << std::endl;
}
run on cpp.sh
Yet another example, going through some options.
// auto mem_fn = static_cast<double (Object::*)() const>(&Object::getter);
// or shorter:
double (Object::*mem_fn)() const = &Object::getter;
// store member function (without instance)
std::function<double(const Object&)> foo = mem_fn;
std::cout << foo(instance) << "\n";
// bind with instance
auto bound = std::bind(mem_fn, &instance);
std::cout << bound() << "\n";
// store member function (with instance)
std::function<double()> bar = bound;
std::cout << bar() << "\n";
// store member function (with instance), without the intermediate steps
std::function<double()> baz =
std::bind(
static_cast<double (Object::*)() const>(&Object::getter),
instance
);
std::cout << baz() << "\n";
I'm trying to write a class that contains a function returning one of the class members, and I want to allow the caller to either move or copy the returned value. I wrote some dummy structs to test this; and after trying different variations, this seems to give me what I want.
#include <iostream>
using namespace std;
struct S {
int x;
S() : x(10) { cout << "ctor called\n"; }
S(const S& s) : x(s.x) { cout << "copy ctor called\n"; }
S(S&& s) : x(s.x) { cout << "move ctor called\n"; }
// I'm implementing move and copy the same way since x is an int.
// I just want to know which one gets called.
};
struct T {
S s;
T() : s() {}
S&& Test() && {
return move(s);
}
const S& Test() & {
return s;
}
};
int main() {
T t;
auto v = move(t).Test();
cout << v.x << "\n";
T t2;
auto w = t2.Test();
cout << w.x << "\n";
return 0;
}
The code prints out (with clang++-5.0 c++14):
ctor called
move ctor called
10
ctor called
copy ctor called
10
Is this an acceptable way to implement what I want? I have a few questions:
In the first Test function, I tried both S&& and S for the return type and it doesn't change the output. Does && mean anything for the (non-template) returned type?
Is it guaranteed that auto v = move(t).Test() would only invalidate the "moved" member? If struct T had other member variables, can I assume this call wouldn't invalidate them?
In the first Test function, I tried both S&& and S for the return type and it doesn't change the output. Does && mean anything for the (non-template) returned type?
There are little differences:
S&& is a (r-value) reference, so object is not yet moved.
returning S would move-construct S, so member is moved once the method is called.
For move(t).Test();, return ingS&& does nothing whereas returning S would move the member.
Is it guaranteed that auto v = move(t).Test() would only invalidate the "moved" member? If struct T had other member variables, can I assume this call wouldn't invalidate them?
Yes, only T::s is moved. std::move is just a cast to rvalue.
Yes it is acceptable way to implement this.
It does the same thing because returned value is temporary object, thus rvalue.
Depends on what you mean by invalidating
In C++ it is valid to use take a const reference to a temporary:
const std::string& s = std::string("abc");
std::cout << s.length() << std::endl; // valid because string instance is still alive
But does this hold true if the temporary was created via a conversion from another type?
For example:
struct Foo
{
~Foo()
{
cout << "Foo destructor?" << endl;
}
};
struct Bar
{
operator Foo()
{
return Foo();
}
~Bar()
{
cout << "Destructor" << endl;
}
};
Foo getFoo()
{
return Foo();
}
Bar getBar()
{
return Bar();
}
int main()
{
const Foo& f = getBar();
/* is f valid here, or is it a dangling reference? */
std::cout << "We're still in main!" << std::endl;
}
I note that Bar's destructor is called before We're still in main is output, which makes me think that Foo& f is a dangling reference. Am I correct?
It does not matter how the temporary was created. If you bind a const X& or an X&& to a local prvalue, the lifetime of the temporary gets extended to the lifetime of the reference.
The function getBar creates an object of type Bar and immediately destroys returning a copy of it.
Bar getBar()
{
return Bar();//the lifetime of Bar() is only on this line;
}
Edit:
For the question in the source code if const Foo & f is valid; yes it is because getBar returns an object copy.
Also after checking the code i see that it first returns a copy of Bar and then casts it to Foo
Also i must mention the RVO (from the comments section) which is an optimization from the compiler. The lifetime of the object is still defined by it's scope {} however in this case the construction is done inside the function and the destruction is outside the function. This optimization will not work of you give a name to the variable like such:
Bar getBar()
{
Bar tmp_value;
return tmp_value;
}
Razvan.
Assuming following code. There is class MyStream witch has template overloaded operator <<. There also is globally overloaded operator MyStream& operator << (MyStream&, const MyClass&). The confusing thing is generating (by compiler) different methods for two almost identical situations (see body of main() function). I supposed that global operator should be used in both cases but it isn't. Why so?
#include <iostream>
class MyStream;
class MyClass;
MyStream& operator << (MyStream& stream, const MyClass&);
class MyStream
{
public:
template <typename T>
MyStream& operator << (const T&)
{
std::cout << __FUNCTION__ << " " << typeid(T).name() << std::endl;
return *this;
}
};
class MyClass
{
};
MyStream& operator << (MyStream& stream, const MyClass&)
{
std::cout << __FUNCTION__ << " " << typeid(MyClass).name() << std::endl;
return stream;
}
int main(int, char**)
{
// 1. Used globally defined operator for MyClass
MyStream() << int() << MyClass();
std::cout << std::endl;
// 2. Template instantiation
MyStream() << MyClass();
std::cin.get();
return 0;
}
Output of program compiled with Microsift Visual C++ Compilers 9.0 (x86):
MyStream::operator << int
operator << class MyClass
MyStream::operator << class MyClass
// 2. Template instantiation
MyStream() << MyClass();
In this case, the expression MyStream() creates a temporary object (a rvalue) which cannot be bound to non-const reference, so the compiler chooses the member function template, because in order to call the free function, the temporary object must be passed as first argument to the function, which is not possible here, as the type of first parameter of the free function is non-const reference. So MyStream << MyClass() invokes member function.
But when you write this:
// 1. Used globally defined operator for MyClass
MyStream() << int() << MyClass();
It first invokes the member function passing int(), and the member function returns an object of type MyStream& which now can be passed to free function as first argument (as it is no more a rvalue, it is now a lvalue), then it invokes the free function, passing object of type MyStream& as first argument and MyClass() as second argument.
This is interesting, and a similar thing happens here:
std::ostringstream printing the address of the c-string instead of its content