I am trying to make a polymorphic vector using std::reference_wrapper for these classes:
struct Int2TypeBase{
virtual void which(){ std::cout << "Int2TypeBase" << "\n";}
};
template <int v>
struct Int2Type : public Int2TypeBase
{
enum
{
value = v
};
void which(){ std::cout << "Int2Type<" << value << ">""\n";}
friend bool operator==(const Int2Type& lhs, const Int2Type& rhs){
return lhs.v == rhs.v;
}
};
Now I am trying to make use of std::reference_wrapper like this:
int main(){
using namespace std;
std::vector<std::reference_wrapper<Int2TypeBase>> v;
Int2Type<0> i2t_1;
v.emplace_back(i2t_1);
auto x = v[0];
x.get().which();
std::cout << typeid(x.get()).name() << "\n";
// std::cout << (x.get() == i2t_1) << "\n";
}
The output is:
Int2Type<0>
8Int2TypeILi0EE
This is what I would expect.
Now however, when I uncomment std::cout << (x.get() == i2t_1) << "\n"; I will get
invalid operands to binary expression ('Int2TypeBase' and 'Int2Type<0>')
This confuses me, as typeid(x.get()).name() returned 8Int2TypeILi0EE rather than F12Int2TypeBasevE which is what I get for typeid(Int2TypeBase()).name();. Furthermore which() also was called for the derived class... so then why does x.get() in x.get() == i2t_1 evaluate to a Int2TypeBase?
Your comparison operator is only defined for derived classes, but the reference wrapper produces (static) type Int2Base, so overload resolution does not even find your comparison operator!
What you probably need is a comparison operator of the form
bool operator==(const Int2TypeBase& lhs, const Int2TypeBase& rhs)
but then you also need to have some sort of polymorphic dispatch to perform the actual comparison (presumably assuming that the dynamic types match).
At compile time, the compiler can only tell that the type of x.get() is Int2TypeBase, because as declared you can put any Int2TypeBase there. So at compile time, it can't determine that the == operator will work.
At run time, the objects you put in the collection reference their full type, so typeid returns what you expect and the correct virtual function is called.
Related
I'm debugging an issue in a large C++ codebase where an attribute of a struct is occasionally being changed to a bad value. Unfortunately, the attribute is public and is accessed or changed in hundreds of places, so simply adding a breakpoint on a mutator is not possible. Also, I don't know the instance of the struct, so adding an address watchpoint wouldn't help.
Instrumenting the code would be a major job. However, a colleague helpfully suggested creating a proxy class which could wrap the existing type in the struct declaration. For example, instead of using MyType _type I would replace this with ChangeProxy<MyType> _type in the struct and the application should compile and work with the proxy taking the place of the direct type in the same manner as, for example, a smart pointer.
However, when I build an example, the implicit conversion operation in the template class doesn't appear to get invoked in type deduction. Here's the code:
#include <iostream>
class MyType {
long _n = 0;
public:
MyType() {}
MyType(const long n) : _n{n} {}
MyType& operator=(const long n) { _n = n; return *this; }
bool isZero() const { return _n != 0; }
};
template <class T>
class ChangeProxy {
public:
ChangeProxy() {}
ChangeProxy(const T& t) : _t{t} {}
ChangeProxy(const T&& t) : _t{std::move(t)} {}
ChangeProxy& operator=(const T& t) {onChange(t); _t = t; return *this;}
ChangeProxy& operator=(const T&& t) {onChange(t); _t = std::move(t); return *this;}
operator T() {return _t;}
private:
T _t;
void onChange(const T& newVal) { /* something here to notify me of changes */ };
};
struct MyStruct {
// MyType _type; // this works ...
ChangeProxy<MyType> _type; // .. but this doesn't
};
int main() {
MyStruct i;
std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
i._type = 1;
std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
return 0;
}
Unfortunately, when I build this I get the following errors:
proxy-variable~test.cpp:35:73: error: ‘class ChangeProxy<MyType>’ has no member named ‘isZero’
35 | std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
| ^~~~~~
proxy-variable~test.cpp:37:73: error: ‘class ChangeProxy<MyType>’ has no member named ‘isZero’
37 | std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
| ^~~~~~
So it seems that the compiler isn't deducing that it can cast a ChangeProxy<MyType> to a MyType. What have I done wrong here?
The context here doesn't let the compiler try out implicit conversions. Calling a member function on some object never does. You can force this by e.g.
std::cout << "i._type.isZero() : " << std::boolalpha <<
static_cast<MyType>(i._type).isZero() << '\n';
// ^^^^^^^^^^^^^^^^^^^ Here, enforce conversion
Another option would be:
MyStruct i;
const MyType& underlying = i._type; // Again, request conversion manually
std::cout << underlying.isZero() << '\n';
What you are doing is invoking a method on the class ChangeProxy<MyType> which indeed doesn't have any method isZero() defined on it, hence the compilation error. You could probably add something like
T const& operator()() const {return _t;}
And then call it using
i._type().isZero()
The reason that the wrapped i._type.isZero() can never work is that implicit conversions of the i._type object aren't considered for direct method calls, and you can't overload operator. like you can operator->.
It's nothing to do with type deduction, there's simply no mechanism in the language to do what you want.
Luckily, you're solving the wrong problem anyway.
... a colleague helpfully suggested creating a proxy class which could wrap the existing type in the struct declaration
Hmm, you didn't mention that here - or am I a colleague now?
an attribute of a struct is occasionally being changed to a bad value
Which attribute? Be specific!
In your code, you're treating the MyType instance as the problematic attribute. However, the only state in MyType is its long _n member.
Writing
class MyType {
ChangeProxy<long> _n = 0;
which is what I actually suggested when I referred to wrapping built-in types, avoids this problem entirely. You may of course need operator!= to make isZero work, but that's a normally overloadable operator.
Oddly the code in your question doesn't permit any mutation of _n anyway, so it's unclear how it can be getting a bad value. However, I assume this is just an artefact of a simplified example.
I wonder, why functional objects in c++ are implemented as templated, with void as default type since c++14.
For example:
https://en.cppreference.com/w/cpp/utility/functional/plus
https://en.cppreference.com/w/cpp/utility/functional/minus
This object in fact performs arithmetic operation +, -, *, /, when called by operator().
The operator() has to be template to work with different types as arguments, but why does the struct have to be?
EDIT
I can create an operator std::plus<>, which may work with a different types in operator():
struct Foo{
int foo;
};
Foo operator+(const Foo& lhs, const Foo& rhs){
return {2 * lhs.foo + 3 * rhs.foo};
}
std::ostream& operator<<(std::ostream& os, const Foo& f){
std::cout << f.foo;
return os;
}
int main()
{
auto op = std::plus<>();
std::cout << op(5, 3) << "\n";
std::cout << op(3.14, 2.71) << "\n";
std::cout << op(Foo(2), Foo(3)) << "\n";
}
And this gives the expected output. Or it may be the case, that having specified the type initially you get something more optimized?
It's a design choice. If you specify the type there is no template operator(), instead the whole class is a template. The operator() is simply something like
constexpr T operator()(const T &lhs, const T &rhs) const
{
return lhs + rhs;
}
This is in several ways different from having a template operator().
If we pass a std::plus<int> it's a plus functor for specifically ints and nothing else.
If we instead passed a std::plus<> without specifying the type it would have a templated operator(). That functor could apply it's operator() to any valid type.
Some advantages with restricting the type from the top of my head:
Since the type is specified the functor can deal with implicit conversion without any issues.
You know for a fact that the functor is not going to silently do things we don't want it to. It's only ever going to do addition on Ts.
Edit
Some examples when the behaviour would differ.
#include <iostream>
#include <functional>
#include <string>
struct Foo {};
int main()
{
auto stringadd = std::plus<std::string>{};
auto anyadd = std::plus<>{};
std::cout << stringadd("hey ", "you") << '\n';
//std::cout << anyadd("hey ", "you") << '\n'; // error: no match for call to '(std::plus<void>) (const char [5], const char [4])'
//std::cout << stringadd("hey ", 1) << '\n'; // error: no match for call to '(std::plus<std::__cxx11::basic_string<char> >) (const char [5], int)'
std::cout << anyadd("hey ", 1) << '\n';
}
I am trying to track the value of a variable that I will input in an API function.
One option is to overload the assignment operator and put some code there. But how would I overload an assigment operator on a member variable of a class?
#include <iostream>
using namespace std;
template <class T>
class MonitoredVariable1
{
public:
MonitoredVariable1() { }
MonitoredVariable1(const T& value) : m_value(value) {}
operator T() const { return m_value; }
T val;
T& operator = (const T& value)
{
val = value;
m_value = value;
std::cout << "value updated" << " \n"; //THIS NEVER GET PRINTED!!!
return val;
}
private:
T m_value;
};
int main()
{
MonitoredVariable1<double> MonitoredVariable;
MonitoredVariable.val = 10.2;
std::cout << "main done..." << " \n";
return 0;
}
To monitor changes to the variable, you need to be assigning to the class, not the contained variable.
First, get rid of val. Only have the private m_value value. This way all accesses have to go thru your member functions that can track the changes.
operator= should return a reference to the class (return *this;), not the value.
Assignment is to the class object:
MonitoredVariable = 10.2;
You can only overload assignment on a class. But you can make that variable to be of a class type with overloaded assignment, like:
class Monitor {
class Monitored {
double x;
public:
Monitored &operator= (double v) {
std::cout << "Assigned " << v << std::endl;
x = v;
return *this; // don’t forget this!
}
operator double() const {
std::cout << "Accessed " << x << std::endl;
return x;
}
};
Monitored val;
};
You may need to overload more operators, and also to pass a reference to Monitor into val (there are tricks to calculate it instead if you’re short on memory).
You can (in modern C++) even overload the & operator, but unless the API function is a template, it has to return pointer. Watching for access through it is very environment-specific.
During debugging, you can usually set a memory watchpoint that will pause program execution on writing to, or even on reading from, a particular memory location (for GDB, see Setting Watchpoints; VS should have a similar feature). That requires hardware support (or debugger-interpreter which is insanely slow), though, so the overall number of watchpoints is often very limited.
Without a debugger, you may be able to make a one-shot watch using memory protection tricks (like protecting the page containing the variable, and unprotecting it on first SEGV) but that’s all too fragile for normal use.
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;
}
friend ostream &operator<<(ostream &output,
const Distance &D)
{
output << "F : " << D.feet << " I : " << D.inches;
return output;
}
Because you don't want the function that writes a instance to a stream to modify the instance.
And because a const reference, unlike a non-const one (unless you're using MSVC) can accept a temporary object, which is useful.
IMHO: passing by reference is more efficient than passing via copy and the const keyword stops you from altering the original instance...
in c++ why we declare reference parameter as const in overloaded
function?
No, in the function that you've posted it's done so for the reasons mentioned in the other answers, but there's no requirement i.e. the standard doesn't mandate that an overloaded function taking a reference parameter should be const.
You're mixing up multiple things here. Overloading is a language feature where multiple functions with identical names can coexist, while const is a qualifier which says the data wouldn't change in a given context through that variable/function. They've no relationship that ties them saying it has to be a const if the overloading function takes a reference paramater. The same goes for reference variables too; they're just an alias (a different name) of another variable which has nothing to do with const or function overloading.
a function signature is a contract between the calling code and the function code.
You want that the function will require as less demands as possible.
If you write demanding signature like
ostream &operator<<(ostream &output, Distance &D)
then you won't be able to call your operator from code that operates on const objects:
void Foo(const Distance& d) {
cout << d; // syntax error
}
in other words putting as less requirements as possible on function arguments makes your function more general.
It is not obligatory to define a reference parameter as const in overloaded functions. Simply in your example of the operator << the right operand is not changed in the function. This allows to use this operator with const objects.
For example
#include <iostream>
class Distance
{
public:
//...
friend ostream &operator<<(ostream &output,
const Distance &D)
{
output << "F : " << D.feet << " I : " << D.inches;
return output;
}
private:
float feet;
//...
};
int main()
{
const Distance d1;
std::cout << d1 << std:;endl;
}
The compiler would issue an error parsing statement
std::cout << d1 << std::endl;
if the second parameter in the operator << would be declared as a non-const reference.
Another example
#include <iostream>
struct A
{
A() {}
A( A & ) { std::cout << "A( A & )" << std::endl; }
A( const A & ) { std::cout << "A( const A & )" << std::endl; }
};
int main()
{
A a1;
A a2( a1 );
const A a3;
A a4( a3 );
}
In this example there are two copy constructors one of which defines the parameter as non-const reference and the other defines the parameter as const reference.
If there would not be the second copy constructor then the compiler would issue an error parsing statement
A a4( a3 );
Safety: with const we make sure we won't accidentaly modify the object.
Speed: References are much faster than passing by value. Also const tells the compiler the object won't be modified, therefore some optimizations could be made.