If I never want an integer to go over 100, is there any simple way to make sure that the integer never exceeds 100, regardless of how much the user adds to it?
For example,
50 + 40 = 90
50 + 50 = 100
50 + 60 = 100
50 + 90 = 100
Try this:
std::min(50 + 40, 100);
std::min(50 + 50, 100);
std::min(50 + 60, 100);
std::min(50 + 90, 100);
http://www.cplusplus.com/reference/algorithm/min/
Another option would be to use this after each operation:
if (answer > 100) answer = 100;
Here is a fairly simple and fairly complete example of a simple ADT for a generic BoundedInt.
It uses boost/operators to avoid writing tedious (const, non-assigning) overloads.
The implicit conversions make it interoperable.
I shunned the smart optimizations (the code therefore stayed easier to adapt to e.g. a modulo version, or a version that has a lower bound as well)
I also shunned the direct templated overloads to convert/operate on mixed instantiations (e.g. compare a BoundedInt to a BoundedInt) for the same reason: you can probably rely on the compiler optimizing it to the same effect anyway
Notes:
you need c++0x support to allow the default value for Max to take effect (constexpr support); Not needed as long as you specify Max manually
A very simple demonstration follows.
#include <limits>
#include <iostream>
#include <boost/operators.hpp>
template <
typename Int=unsigned int,
Int Max=std::numeric_limits<Int>::max()>
struct BoundedInt : boost::operators<BoundedInt<Int, Max> >
{
BoundedInt(const Int& value) : _value(value) {}
Int get() const { return std::min(Max, _value); }
operator Int() const { return get(); }
friend std::ostream& operator<<(std::ostream& os, const BoundedInt& bi)
{ return std::cout << bi.get() << " [hidden: " << bi._value << "]"; }
bool operator<(const BoundedInt& x) const { return get()<x.get(); }
bool operator==(const BoundedInt& x) const { return get()==x.get(); }
BoundedInt& operator+=(const BoundedInt& x) { _value = get() + x.get(); return *this; }
BoundedInt& operator-=(const BoundedInt& x) { _value = get() - x.get(); return *this; }
BoundedInt& operator*=(const BoundedInt& x) { _value = get() * x.get(); return *this; }
BoundedInt& operator/=(const BoundedInt& x) { _value = get() / x.get(); return *this; }
BoundedInt& operator%=(const BoundedInt& x) { _value = get() % x.get(); return *this; }
BoundedInt& operator|=(const BoundedInt& x) { _value = get() | x.get(); return *this; }
BoundedInt& operator&=(const BoundedInt& x) { _value = get() & x.get(); return *this; }
BoundedInt& operator^=(const BoundedInt& x) { _value = get() ^ x.get(); return *this; }
BoundedInt& operator++() { _value = get()+1; return *this; }
BoundedInt& operator--() { _value = get()-1; return *this; }
private:
Int _value;
};
Sample usage:
typedef BoundedInt<unsigned int, 100> max100;
int main()
{
max100 i = 1;
std::cout << (i *= 10) << std::endl;
std::cout << (i *= 6 ) << std::endl;
std::cout << (i *= 2 ) << std::endl;
std::cout << (i -= 40) << std::endl;
std::cout << (i += 1 ) << std::endl;
}
Demo output:
10 [hidden: 10]
60 [hidden: 60]
100 [hidden: 120]
60 [hidden: 60]
61 [hidden: 61]
Bonus material:
With a fully c++11 compliant compiler, you could even define a Userdefined Literal conversion:
typedef BoundedInt<unsigned int, 100> max100;
static max100 operator ""_b(unsigned int i)
{
return max100(unsigned int i);
}
So that you could write
max100 x = 123_b; // 100
int y = 2_b*60 - 30; // 70
Yes.
As a bare minimum, you could start with this:
template <int T>
class BoundedInt
{
public:
explicit BoundedInt(int startValue = 0) : m_value(startValue) {}
operator int() { return m_value; }
BoundedInt operator+(int rhs)
{ return BoundedInt(std::min((int)BoundedInt(m_value + rhs), T)); }
private:
int m_value;
};
You can write your own class IntegerRange that includes overloaded operator+, operator-, etc. For an example of operator overloading, see the complex class here.
The simplest way would be to make a class that holds the value, rather than using an integer variable.
class LimitedInt
{
int value;
public:
LimitedInt() : value(0) {}
LimitedInt(int i) : value(i) { if (value > 100) value = 100; }
operator int() const { return value; }
LimitedInt & operator=(int i) { value = i; if (value > 100) value = 100; return *this; }
};
You might get into trouble with results not matching expectations. What should the result of this be, 70 or 90?
LimitedInt q = 2*60 - 30;
C++ does not allow overriding (re-defining) operators on primitive types.
If making a custom integer class (as suggested above) does not fall under your definition of a "simple way", then the answer to your question is no, there is no simple way to do what you want.
I know it's an old post but I think it could still be usefull for some people. I use this to set upper and lower bound:
bounded_value = max(min(your_value,upper_bound),lower_bound);
You could use it in a function like this:
float bounded_value(float x, float upper, float under){
return max(min(x,upper),lower);
}
Related
Consider the following program:
#include <iostream>
#include <boost/icl/interval_map.hpp>
struct Value
{
explicit Value(int v) : v(v), is_empty(false) {}
Value() : v(0), is_empty(true) {}
Value& operator+=(const Value& other)
{
v += other.v;
return *this;
}
bool operator==(const Value& other) const { return is_empty == other.is_empty; }
bool operator!=(const Value& other) const { return is_empty != other.is_empty; }
int v;
bool is_empty;
};
int main()
{
boost::icl::interval_map<int, Value> m;
m.add(std::make_pair(boost::icl::interval<int>::right_open(10, 20), Value(2)));
m.add(std::make_pair(boost::icl::interval<int>::right_open(15, 30), Value(3)));
std::cout << m.iterative_size() << '\n';
std::cout << m.begin()->first.lower() << '\n';
std::cout << m.begin()->first.upper() << '\n';
std::cout << m.begin()->second.v << '\n';
}
The output is
1
10
30
2
Questons:
Why is the last line 2?
Isn't the interval map expected to add up the value, so that it is 5?
How to achieve the behavior that intervals are added and the value from += is preserved?
I want the following results:
{([10,20)->(2))+
([15,30)->(3))+
([40,50)->(11))}
=
{([10,30)->(5))([40,50)->(11))}
That is, when intervals are added, they are merged, and the combined value is stored for entire merged interval.
There's may be no math sense in this operation, but this is what I need in my program. (Also, I don't to subtract intervals).
The problem is that
bool operator==(const Value& other) const { return is_empty == other.is_empty; }
bool operator!=(const Value& other) const { return is_empty != other.is_empty; }
make it so that ANY value is "identical". That makes the behaviour unspecified, and likely ends up merging any touching intervals and keeping the previous value (because it was "equal" according to your own operator==).
Let's have C++ generate a more correct comparison:
struct Value {
explicit Value(int v) : value(v) {}
Value() : is_empty(true) {}
Value& operator+=(const Value& other) { value += other.value; return *this; }
auto operator<=>(Value const&) const = default;
bool is_empty = false;
int value = 0;
};
Now you can Live On Compiler Explorer
#include <iostream>
#include <boost/icl/interval_map.hpp>
int main()
{
namespace icl = boost::icl;
using I = icl::interval<int>;
using Value = int;
auto const a = std::make_pair(I::right_open(10, 20), Value(2));
auto const b = std::make_pair(I::right_open(15, 30), Value(3));
auto const c = std::make_pair(I::right_open(40, 50), Value(11));
icl::interval_map<int, Value> m;
m.add(a);
m.add(b);
m.add(c);
std::cout << m << "\n";
m.subtract(a);
std::cout << m << "\n";
}
Printing
{([10,15)->(2))([15,20)->(5))([20,30)->(3))([40,50)->(11))}
However, I'm struggling to understand what Value adds over optional<int> which, in fact is already the behaviour of the interval_map anyways:
int main()
{
namespace icl = boost::icl;
using I = icl::interval<int>;
auto const a = std::make_pair(I::right_open(10, 20), 2);
auto const b = std::make_pair(I::right_open(15, 30), 3);
auto const c = std::make_pair(I::right_open(40, 50), 11);
icl::interval_map<int, int> m;
m.add(a);
m.add(b);
m.add(c);
std::cout << m << "\n";
m.subtract(a);
std::cout << m << "\n";
}
Prints:
{([10,15)->2)([15,20)->5)([20,30)->3)([40,50)->11)}
{([15,30)->3)([40,50)->11)}
In fact, in some respects, your custom Value take seems "wrong" to me, evem with the fixed comparison:
Live On Compiler Explorer
#include <iostream>
#include <boost/icl/interval_map.hpp>
struct Value {
explicit Value(int v) : value(v) {}
Value() : is_empty(true) {}
Value& operator+=(const Value& other) { value += other.value; return *this; }
Value& operator-=(const Value& other) { value -= other.value; return *this; }
auto operator<=>(Value const&) const = default;
bool is_empty = false;
int value = 0;
friend std::ostream& operator<<(std::ostream& os, Value const& v) {
return v.is_empty ? os << "#EMPTY" : os << v.value;
}
};
int main()
{
namespace icl = boost::icl;
using I = icl::interval<int>;
auto const a = std::make_pair(I::right_open(10, 20), Value(2));
auto const b = std::make_pair(I::right_open(15, 30), Value(3));
auto const c = std::make_pair(I::right_open(40, 50), Value(11));
icl::interval_map<int, Value> m;
m.add(a);
m.add(b);
m.add(c);
std::cout << m << "\n";
m.subtract(a);
std::cout << m << "\n";
}
Printing
{([10,15)->2)([15,20)->5)([20,30)->3)([40,50)->11)}
{([10,15)->0)([15,30)->3)([40,50)->11)}
Is [10,15)->0 really intended, desired?
This is my own attempt on a pragmatic answer only on the last question:
How to achieve the behavior that intervals are added and the value from += is preserved?
I found another implementation, way simpler, but that can be easily customized to the behavior I want. It takes interval type as template parameter, and uses method join to join intervals, so I specialize it with my own interval type, which adds the value and on join sums the value:
#include <iostream>
#include "interval_tree.hpp"
using iv_base = lib_interval_tree::interval<int, lib_interval_tree::right_open>;
struct iv_t : iv_base
{
int value;
iv_t(const iv_base& base, int v)
: iv_base(base)
, value(v)
{
}
iv_t(value_type low, value_type high, int v)
: iv_base(low, high)
, value(v)
{
}
iv_t join(iv_t const& other) const
{
return iv_t(iv_base::join(other), value + other.value);
}
};
using it_t = lib_interval_tree::interval_tree<iv_t>;
int main()
{
it_t it;
it.insert_overlap(iv_t( 10, 20, 2 ));
it.insert_overlap(iv_t{ 15, 30, 3 });
it.insert_overlap(iv_t{ 40, 50, 11 });
for (decltype(auto) v : it)
{
std::cout << v.low() << ".." << v.high() << ":" << v.value << "\n";
}
}
The output is:
10..30:5
40..50:11
Totally possible Boost.Icl can be customized for the same behavior, but it is more complex to understand if it is possible and how to do it.
I need a function to add values to v[i] using the operator+
the vector v contains the values 10,2 and 3.
#include <iostream>
#include <vector>
template<typename T>
class Measurement
{
private:
T val;
public:
Measurement(T a)
: val{ a }
{}
T value() const { return val; }
Measurement<T>& operator+(const T& nr)
{
//... ???
return *this;
}
};
int main()
{
//create a vector with values (10,2,3)
std::vector<Measurement<int>> v{ 10,2,3 };
v[2] + 3 + 2; //add at v[2] value 5
for (const auto& m : v) std::cout << m.value() << ",";
return 0;
}
The result must be 10,2,8
Just add the val of the instance to other nr
Measurement<T>& operator+(const T& nr)
{
this->val += nr;
return *this;
}
However, overloading the operator+ for this might be misleading and should be avoiding such. Therefore I would suggest the traditional way
Measurement<T> operator+(const T& nr)
{
Measurement<T> tmp{ *this };
tmp.val += nr;
return tmp; // returns the temporary, which you need to reassign!
}
and do
v[2] = v[2] + 3 + 2;
for the required result.
Or even better provide operator+= which meant does return the reference to the Measurement<T>
Measurement<T>& operator+=(const T& nr)
{
this->val += nr;
return *this;
}
and call it like
v[2] += 3 + 2;
I'm defining classes as stand-ins for hardware registers in a Windows PC-based simulation environment for embedded code. To work seamlessly and appear to the embedded firmware code as if they were hardware registers, the classes have to implicitly convert to/from their appropriate standard fixed-width types (uint8_t, uint16_t, uint32_t, and their signed counterparts), based on the size & type of the hardware register.
The classes work beautifully (with the help of this SO answer) except that the compiler can't figure out that it needs to do the implicit conversion to handle += operations when two such types are combined in a += operation:
#include <iostream>
class REG16
{
private:
uint16_t _i;
public:
REG16() = default;
constexpr REG16(const unsigned int i) : _i((uint16_t)i * 2) {}
constexpr operator uint16_t() const { return _i / 2; }
REG16& operator=(const unsigned int i) { _i = (uint16_t)i * 2; }
};
class REG32
{
private:
uint32_t _i;
public:
REG32() = default;
constexpr REG32(const uint32_t i) : _i(i * 2) {}
constexpr operator uint32_t() const { return _i / 2; }
REG32& operator=(const uint32_t i) { _i = i * 2; return *this; }
};
int main()
{
REG16 a(12);
REG32 b(12);
uint32_t c;
REG32 d;
// Works great: 'a' is implicitly converted to a uint16_t, then added to 'c':
c = 0;
c += a;
std::cout << "c = 0; c += a; result: c = " << c << std::endl;
// Works great: 'b' is implicitly converted to a uint32_t, then added to 'c':
c = 0;
c += b;
std::cout << "c = 0; c += b; result: c = " << c << std::endl;
// Works great: 'b' and 'd' are both implicitly converted to uint32_t's,
// then added together as uint32_t's, and assigned back to 'd' with the
// REG32::operator=() asignment operator:
d = 0;
d = d + b;
std::cout << "d = 0; d += b; result: d = " << d << std::endl;
// Does not work:
// error C2676: binary '+=': 'REG32' does not define this operator or a conversion to a type acceptable to the predefined operator
d = 0;
d += b; // <------ line with the error
std::cout << "d = 0; d += b; result: d = " << d << std::endl;
}
As demonstrated above, instead of d += b; I could just do d = d + b; but the whole purpose of these classes is to operate the same as a real hardware register would, one that's defined as a uint8_t, uint16_t, uint32_t, etc. for the simulation & testing environment. I don't want to impose strange restrictions on the embedded firmware just to be able to run in the simulation environment.
Is there something I can change or add to my classes to enable the compiler to do the appropriate implicit conversions to enable use of the built-in operator+= that's built-in for the standard types? I'd like to avoid having to define my own operator+= methods for combinations of these classes because that's a lot of permutations to have to handle; I'd rather the compiler's implicit conversions do the work for me.
I struggled with the problem about 25 years ago. Tonight I searched for a template that I wrote back then to help with such things. I would give it to you, but I regret that it's probably lost. It was a mix-in, something vaguely like the one below. I think it at least solves the proliferation-of-operator-signatures problem.
Thanks to Ben Voigt for suggesting CRTP.
Thanks to Jens for improving the code.
Thanks to Mike Kinghan for the regression testing.
#include <cstdint>
using std::uint32_t;
using std::uint16_t;
template<typename Derived, typename Value_t>
class number {
public:
constexpr number(Value_t& x) : i(x) {}
template<class R>
Derived&
operator+= (const R& r) {
i += static_cast<Value_t>(r); return static_cast<Derived&>(*this);
}
// ... and scads of other operators that I slavishly typed out.
protected:
~number() {} // to prevent slicing
private:
Value_t & i;
};
class REG16: public number<REG16, uint16_t>
{
private:
uint16_t _i;
using Num = number<REG16, uint16_t>;
public:
REG16() : Num(_i) {}
constexpr REG16(const unsigned int i) : _i(i), Num(_i) {}
constexpr operator uint16_t() const { return _i; }
REG16& operator=(const unsigned int i) { _i = i; }
};
class REG32 : public number<REG32, uint32_t>
{
private:
uint32_t _i;
using Num = number<REG32, uint32_t>;
public:
REG32() : Num(_i) {}
constexpr REG32(const uint32_t i) : _i(i), Num(_i) {}
constexpr operator uint32_t() const { return _i; }
REG32& operator=(const uint32_t i) { _i = i; return *this; }
};
#include <iostream>
int main()
{
REG16 a(12);
REG32 b(12);
uint32_t c;
REG32 d;
// Works great: 'a' is implicitly converted to a uint16_t, then added to 'c':
c = 0;
c += a;
std::cout << "c = 0; c += a; result: c = " << c << std::endl;
// Works great: 'b' is implicitly converted to a uint32_t, then added to 'c':
c = 0;
c += b;
std::cout << "c = 0; c += b; result: c = " << c << std::endl;
// Works great: 'b' and 'd' are both implicitly converted to uint32_t's,
// then added together as uint32_t's, and assigned back to 'd' with the
// REG32::operator=() asignment operator:
d = 0;
d = d + b;
std::cout << "d = 0; d += b; result: d = " << d << std::endl;
// DID NOT WORK
// error C2676: binary '+=': 'REG32' does not define this operator or a conversion to a type acceptable to the predefined operator
d = 0;
d += b; // <------ line that had the error
std::cout << "d = 0; d += b; result: d = " << d << std::endl;
}
UPDATE by phonetagger:
This is what I actually ended up using as the base class for every REG class:
// numericCompoundAssignmentBase is a template base class for use with types that implement numeric behavior
template<typename DT, typename NT> // DerivedType, NativeType (native types: uint8_t, uint16_t, etc.)
struct numericCompoundAssignmentBase
{
NT operator++ (int) { DT& dt = static_cast<DT&>(*this); NT x(dt); dt = x + 1; return x; } // postfix ++
NT operator-- (int) { DT& dt = static_cast<DT&>(*this); NT x(dt); dt = x - 1; return x; } // postfix --
DT& operator++ () { DT& dt = static_cast<DT&>(*this); NT x(dt); dt = x + 1; return dt; } // prefix --
DT& operator-- () { DT& dt = static_cast<DT&>(*this); NT x(dt); dt = x - 1; return dt; } // prefix --
DT& operator+= (const NT& r) { DT& dt = static_cast<DT&>(*this); dt = dt + r; return dt; }
DT& operator-= (const NT& r) { DT& dt = static_cast<DT&>(*this); dt = dt - r; return dt; }
DT& operator*= (const NT& r) { DT& dt = static_cast<DT&>(*this); dt = dt * r; return dt; }
DT& operator/= (const NT& r) { DT& dt = static_cast<DT&>(*this); dt = dt / r; return dt; }
DT& operator%= (const NT& r) { DT& dt = static_cast<DT&>(*this); dt = dt % r; return dt; }
DT& operator&= (const NT& r) { DT& dt = static_cast<DT&>(*this); dt = dt & r; return dt; }
DT& operator|= (const NT& r) { DT& dt = static_cast<DT&>(*this); dt = dt | r; return dt; }
DT& operator^= (const NT& r) { DT& dt = static_cast<DT&>(*this); dt = dt ^ r; return dt; }
DT& operator<<=(const NT& r) { DT& dt = static_cast<DT&>(*this); dt = dt << r; return dt; }
DT& operator>>=(const NT& r) { DT& dt = static_cast<DT&>(*this); dt = dt >> r; return dt; }
private: numericCompoundAssignmentBase() = default; friend DT; // ensures the correct 'DT' was specified
};
Reading #JiveJadson's answer, I was wondering - why not just have a single templated class?
template<typename Integer>
class register_t {
public:
using value_type = Integer;
register_t(Integer& val) : value_(val << 1) {}
register_t(const register_t&) = default;
register_t(register_t&&) = default;
register_t& operator=(const register_t&) = default;
register_t& operator=(register_t&&) = default;
operator Integer() { return value_ >> 1; }
template <typename RHSInteger>
register_t& operator+= (const RHSInteger& rhs) {
value_ += static_cast<Integer>(rhs) << 1;
return value_;
}
private:
Integer value_;
// bottom bit is 0, rest of bits hold the actual value
};
I'd like to avoid having to define my own operator+= methods for combinations of
these classes because that's a lot of permutations to have to handle
But the compiler can handle them all for you. To a first approximation:
#include <iostream>
#include <cstdint>
class REG16
{
private:
uint16_t _i;
public:
REG16() = default;
constexpr REG16(const unsigned int i) : _i((uint16_t)i * 2) {}
constexpr operator uint16_t() const { return _i / 2; }
REG16& operator=(const unsigned int i) { _i = (uint16_t)i * 2; return *this; }
template<typename T>
REG16& operator+=(T && lhs) {
return *this = *this + std::forward<T>(lhs);
}
};
class REG32
{
private:
uint32_t _i;
public:
REG32() = default;
constexpr REG32(const uint32_t i) : _i(i * 2) {}
constexpr operator uint32_t() const { return _i / 2; }
REG32& operator=(const uint32_t i) { _i = i * 2; return *this; }
template<typename T>
REG32& operator+=(T && lhs) {
return *this = *this + std::forward<T>(lhs);
}
};
Live VC++
Live GCC
If you or anyone else writes code that attempts to instantiate:
template<typename T>
REG{16|32}& operator+=(T && lhs) {
return *this = *this + std::forward<T>(lhs);
}
with a type T for which:
*this + lhs
is not defined then it simply won't compile.
But this solution draws further attention to the fact that REG16 and REG32
are identical modulo the type of the member _i. So better still just make
each of them a specialization of one template:
#include <utility>
#include <cstdint>
template<typename IntType>
struct REG_N
{
REG_N() = default;
constexpr REG_N(const IntType i)
: _i(static_cast<IntType>(i) * 2) {}
constexpr operator IntType() const {
return _i / 2;
}
REG_N & operator=(const IntType i) {
_i = static_cast<IntType>(i) * 2;
return *this;
}
template<typename T>
REG_N & operator+=(T && lhs) {
return *this = *this + std::forward<T>(lhs);
}
private:
IntType _i;
};
using REG16 = REG_N<std::uint16_t>;
using REG32 = REG_N<std::uint32_t>;
Live VC++
Live GCC
I know of const, that can't be changed after creation. But I was wondering if there is a way to declare a variable that you set only once and after that, can't overwrite.
In my code, I would like to avoid the bool variable by having an nFirst that, once set to nIdx, can't be set to the new value of nIdx.
My code:
int nFirst = 0;
int nIdx = 0;
bool bFound = false;
BOOST_FOREACH(Foo* pFoo, aArray)
{
if (pFoo!= NULL)
{
pFoo->DoSmth();
if (!bFound)
{
nFirst= nIdx;
bFound = true;
}
}
nIdx++;
}
Pretty easy to roll your own.
template<typename T>
class SetOnce
{
public:
SetOnce(T init) : m_Val(init)
{}
SetOnce<T>& operator=(const T& other)
{
std::call_once(m_OnceFlag, [&]()
{
m_Val = other;
});
return *this;
}
const T& get() { return m_Val; }
private:
T m_Val;
std::once_flag m_OnceFlag;
};
Then just use the wrapper class for your variable.
SetOnce<int> nFirst(0);
nFirst= 1;
nFirst= 2;
nFirst= 3;
std::cout << nFirst.get() << std::endl;
Outputs:
1
I would like to avoid the bool variable
You can check nFirst itself, based on the fact that it won't be set a negative number. Such as:
int nFirst = -1;
int nIdx = 0;
BOOST_FOREACH(Foo* pFoo, aArray)
{
if (pFoo != NULL)
{
pFoo->DoSmth();
if (nFirst == -1)
{
nFirst = nIdx;
}
}
nIdx++;
}
Similar to cocarin's, but throws exception instead of silently ignoring assignment:
template <typename T, typename Counter = unsigned char>
class SetOnce {
public:
SetOnce(const T& initval = T(), const Counter& initcount = 1):
val(initval), counter(initcount) {}
SetOnce(const SetOnce&) = default;
SetOnce<T, Counter>& operator=(const T& newval) {
if (counter) {
--counter;
val = newval;
return *this;
}
else throw "Some error";
}
operator const T&() const { return val; } // "getter"
protected:
T val;
Counter counter;
};
Usage:
SetOnce<int> x = 42;
std::cout << x << '\n'; // => 42
x = 4;
// x = 5; // fails
std::cout << x << '\n'; // => 4
Online demo
Your question is about avoiding the bool but also implies the need for const-ness.
To avoid the bool, I'd use a boost::optional like this:
boost::optional<int> nFirst;
// ..
if (!nFirst) nFirst = nIdx;
// and now you can use *nFirst to get its value
Then, you can enforce logical (rather than literal) const-ness like this:
const boost::optional<int> nFirst;
// ..
if (!nFirst) const_cast<boost::optional<int>&>(nFirst) = nIdx;
// you can use *nFirst to get the value, any attempt to change it would cause a compile-time error
Using const_cast is not the safest practice, but in your particular case and as long as you only do it once it'd be OK. It simplifies both your code and your intentions: you do want a const, it's just that you want to defer it's initialisation for a bit.
Now, as songyuanyao suggested, you could directly use an int instead of a boost::optional, but the latter makes your intention explicit so I think it's better this way. In the end of day this is C++ while songyuanyao's solution is really a C-style one.
This is set once template. You can use this class as assurance that the value will be set and saved only once. Every next try will be canceled.
#include <iostream>
using namespace std;
template <class T>
class SetOnce;
template<class T>
std::ostream& operator<<( ostream& os, const SetOnce<T>& Obj );
template <class T>
class SetOnce
{
public:
SetOnce() {set = false; }
~SetOnce() {}
void SetValue(T newValue) { value = !set ? newValue : value; set = true; }
private:
T value;
bool set;
friend std::ostream& operator<< <>( ostream& os, const SetOnce& Obj );
public:
SetOnce<T>& operator=( const T& newValue )
{
this->SetValue(newValue);
return *this;
}
};
template<class T>
std::ostream& operator<<( ostream& os, const SetOnce<T>& Obj )
{
os << Obj.value;
return os;
}
Use case:
int main()
{
SetOnce<bool> bvar;
SetOnce<int> ivar;
SetOnce<std::string> strvar;
std::cout<<"initial values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
bvar = false; //bvar.SetValue(false);
ivar = 45; //ivar.SetValue(45);
strvar = "Darth Vader"; //strvar.SetValue("Darth Vader");
std::cout<<"set values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
bvar = true; //bvar.SetValue(true);
ivar = 0; //ivar.SetValue(0);
strvar = "Anakin"; //strvar.SetValue("Anakin");
std::cout<<"set again values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
return 0;
}
How do I have properties in C++ class, as you have in a C# class.
I don't want to have getter and setter methods.
You can use a solution similar to that Jon suggested, yet retaining ordinary C++ semantics using operator overloading. I've slightly modified Jon's code as following (explanations follow the code):
#include <iostream>
template<typename T>
class Accessor {
public:
explicit Accessor(const T& data) : value(data) {}
Accessor& operator=(const T& data) { value = data; return *this; }
Accessor& operator=(const Accessor& other) { this->value = other.value; return *this; }
operator T() const { return value; }
operator T&() { return value; }
private:
Accessor(const Accessor&);
T value;
};
struct Point {
Point(int a = 0, int b = 0) : x(a), y(b) {}
Accessor<int> x;
Accessor<int> y;
};
int main() {
Point p;
p.x = 10;
p.y = 20;
p.x++;
std::cout << p.x << "," << p.y << std::endl;
p.x = p.y = 15;
std::cout << p.x << "," << p.y << std::endl;
return 0;
}
We overload operator= to retain the usual assignment syntax instead of a function-call-like syntax. We use the cast operator as a "getter". We need the second version of the operator= to allow assignment of the second kind in main().
Now you can add to Accessor's constructor function pointers, or better - functors - to call as getters/setters in any way seems right to you. The following example assumes the setter function return bool to convey agreement to setting the new value, and the getter can just modify it on it's way out:
#include <iostream>
#include <functional>
#include <cmath>
template<typename T>
class MySetter {
public:
bool operator()(const T& data)
{
return (data <= 20 ? true : false);
}
};
template<typename T>
class MyGetter {
public:
T operator()(const T& data)
{
return round(data, 2);
}
private:
double cint(double x) {
double dummy;
if (modf(x,&dummy) >= 0.5) {
return (x >= 0 ? ceil(x) : floor(x));
} else {
return (x < 0 ? ceil(x) : floor(x));
}
}
double round(double r, int places) {
double off = pow(10.0L, places);
return cint(r*off)/off;
}
};
template<typename T, typename G = MyGetter<T>, typename S = MySetter<T>>
class Accessor {
public:
explicit Accessor(const T& data, const G& g = G(), const S& s = S()) : value(data), getter(g), setter(s) {}
Accessor& operator=(const T& data) { if (setter(data)) value = data; return *this; }
Accessor& operator=(const Accessor& other) { if (setter(other.value)) this->value = other.value; return *this; }
operator T() const { value = getter(value); return value;}
operator T&() { value = getter(value); return value; }
private:
Accessor(const Accessor&);
T value;
G getter;
S setter;
};
struct Point {
Point(double a = 0, double b = 0) : x(a), y(b) {}
Accessor<double> x;
Accessor<double> y;
};
int main() {
Point p;
p.x = 10.712;
p.y = 20.3456;
p.x+=1;
std::cout << p.x << "," << p.y << std::endl;
p.x = p.y = 15.6426;
std::cout << p.x << "," << p.y << std::endl;
p.x = p.y = 25.85426;
std::cout << p.x << "," << p.y << std::endl;
p.x = p.y = 19.8425;
p.y+=1;
std::cout << p.x << "," << p.y << std::endl;
return 0;
}
However, as the last line demonstrates it has a bug. The cast operator returning a T& allows users to bypass the setter, since it gives them access to the private value. One way to solve this bug is to implement all the operators you want your Accessor to provide. For example, in the following code I used the += operator, and since I removed the cast operator returning reference I had to implement a operator+=:
#include <iostream>
#include <functional>
#include <cmath>
template<typename T>
class MySetter {
public:
bool operator()(const T& data) const {
return (data <= 20 ? true : false);
}
};
template<typename T>
class MyGetter {
public:
T operator() (const T& data) const {
return round(data, 2);
}
private:
double cint(double x) const {
double dummy;
if (modf(x,&dummy) >= 0.5) {
return (x >= 0 ? ceil(x) : floor(x));
} else {
return (x < 0 ? ceil(x) : floor(x));
}
}
double round(double r, int places) const {
double off = pow(10.0L, places);
return cint(r*off)/off;
}
};
template<typename T, typename G = MyGetter<T>, typename S = MySetter<T>>
class Accessor {
private:
public:
explicit Accessor(const T& data, const G& g = G(), const S& s = S()) : value(data), getter(g), setter(s) {}
Accessor& operator=(const T& data) { if (setter(data)) value = data; return *this; }
Accessor& operator=(const Accessor& other) { if (setter(other.value)) this->value = other.value; return *this; }
operator T() const { return getter(value);}
Accessor& operator+=(const T& data) { if (setter(value+data)) value += data; return *this; }
private:
Accessor(const Accessor&);
T value;
G getter;
S setter;
};
struct Point {
Point(double a = 0, double b = 0) : x(a), y(b) {}
Accessor<double> x;
Accessor<double> y;
};
int main() {
Point p;
p.x = 10.712;
p.y = 20.3456;
p.x+=1;
std::cout << p.x << "," << p.y << std::endl;
p.x = p.y = 15.6426;
std::cout << p.x << "," << p.y << std::endl;
p.x = p.y = 25.85426;
std::cout << p.x << "," << p.y << std::endl;
p.x = p.y = 19.8425;
p.y+=1;
std::cout << p.x << "," << p.y << std::endl;
return 0;
}
You'll have to implements all the operators you're going to use.
For behaviour that's kind of like this, I use a templated meta-accessor. Here's a highly simplified one for POD types:
template<class T>
struct accessor {
explicit accessor(const T& data) : value(data) {}
T operator()() const { return value; }
T& operator()() { return value; }
void operator()(const T& data) { value = data; }
private:
accessor(const accessor&);
accessor& operator=(const accessor&);
T value;
};
Typical usage is like this:
struct point {
point(int a = 0, int b = 0) : x(a), y(b) {}
accessor<int> x;
accessor<int> y;
};
point p;
p.x(10);
p.y(20);
p.x()++;
std::cout << p.x();
The compiler typically inlines these calls if you set things up right and have optimisation turned on. It's no more of a performance bottleneck than using actual getters and setters, no matter what optimisations happen. It is trivial to extend this to automatically support non-POD or enumerated types, or to allow callbacks to be registered for whenever data are read or written.
Edit: If you prefer not to use the parentheses, you can always define operator=() and an implicit cast operator. Here's a version that does just that, while also adding basic "stuff happened" callback support:
Further Edit: Okay, totally missed that someone already made a revised version of my code. Sigh.
If you don't care that your C++ code won't compile with anything other than the Microsoft Visual C++ compiler, then you can use some of the compiler's non-standard extensions.
For instance, the following code will create a C#-like property called MyProperty.
struct MyType
{
// This function pair may be private (for clean encapsulation)
int get_number() const { return m_number; }
void set_number(int number) { m_number = number; }
__declspec(property(get=get_number, put=set_number)) int MyProperty;
private:
int m_number:
}
int main()
{
MyType m;
m.MyProperty = 100;
return m.MyProperty;
}
More information on this Microsoft-specific language extension is available here.
Here's a PoC implementation I did a while back, works nicely except that you need to set something up in the constructor for it to work nice and smoothly.
http://www.codef00.com/code/Property.h
Here's the example usage:
#include <iostream>
#include "Property.h"
class TestClass {
public:
// make sure to initialize the properties with pointers to the object
// which owns the property
TestClass() : m_Prop1(0), m_Prop3(0.5), prop1(this), prop2(this), prop3(this) {
}
private:
int getProp1() const {
return m_Prop1;
}
void setProp1(int value) {
m_Prop1 = value;
}
int getProp2() const {
return 1234;
}
void setProp3(double value) {
m_Prop3 = value;
}
int m_Prop1;
double m_Prop3;
public:
PropertyRW<int, TestClass, &TestClass::getProp1, &TestClass::setProp1> prop1;
PropertyRO<int, TestClass, &TestClass::getProp2> prop2;
PropertyWO<double, TestClass, &TestClass::setProp3> prop3;
};
and some usage of this class...
int main() {
unsigned int a;
TestClass t;
t.prop1 = 10;
a = t.prop1;
t.prop3 = 5;
a = t.prop2;
std::cout << a << std::endl;
return 0;
}
There are two annoyances with this approach:
You need to give the property a
pointer to its owning class.
The syntax to declare a property is a
bit verbose, but I bet I can clean
that up a bit with some macros
You don't. C++ doesn't support properties like C# does. If you want code to run on set/get, it will have to be a method.
Properties aren't supported in C++, but you can implement them:
1) By using templates
2) By making language extension and writing custom code preprocessor
Either approach won't be easy, but it can be done.
You could provide get and set methods that have similar names to the data members:
class Example
{
private:
unsigned int x_;
double d_;
std::string s_s;
public:
unsigned int x(void) const
{ return x_;}
void x(unsigned int new_value)
{ x_ = new_value;}
double d(void) const
{ return d_;}
void d(double new_value)
{ d_ = new_value;}
const std::string& s(void) const
{ return s_;}
void s(const std::string& new_value)
{ s_ = new_value;}
};
Although this comes close, as it requires using '()' for each member, it doesn't meet the exact functionality of properties that Microsoft Languages provide.
The closest match for properties is to declare the data members as public.
Here’s a bit crude and simple implementation using a preprocessor macro to effortlessly generate nested classes that provide the functionality of getters and setters with the nice and clean syntax as if they were actual variables. No templates or function pointers are used (if that’s a plus), although your compiled program will have as many (sub)classes of the name property_* as there are PROPERTIES declarations, and like in Evan Teran’s solution, you need to give the property a reference to the owning class in the constructor.
More operators (operator++, operator+=) should be easy to add.
(I guess the reference to the owning class is ok, despite the circularity...? (x.property_age.x.property_age ...))
#include <iostream>
#include <stdexcept>
#define PROPERTY(type, name, owner, get_exprs, set_exprs) \
friend class property_ ##name; \
class property_ ##name { \
owner & x; \
public: \
property_ ##name (owner & init): x(init) {} \
operator type () { \
get_exprs \
} \
type operator= (const type value) { \
set_exprs \
return value; \
} \
} name ;
int current_year = 2020;
class person {
int year_of_birth; // Integer is signed to demonstrate argument validation
public:
// Remember to add each property and *this for them
person(): year_of_birth(0), age(*this) {}
const int& born() { return year_of_birth; }
// Remember the semicolons
PROPERTY(int, age, person,
/*get:*/ return current_year - x.year_of_birth; ,
/*set:*/ if (value < 0) throw std::invalid_argument("person::age : age cannot be negative");
x.year_of_birth = current_year - value; )
};
int main() {
person alice, bob;
alice.age = bob.age = 28;
alice.age = alice.age + 5;
//alice.age = -7; //throws
// Apparently the compiler does nice implicit conversion from
// (the macro-generated class) 'property_age' to 'int'
std::cout << "Alice: born: " << alice.born() << ", age: " << alice.age << '\n'
<< "Bob: born: " << bob.born() << ", age: " << bob.age << '\n'
<< "The mean of their ages is: " << (alice.age + bob.age) / 2.0 << '\n';
return 0;
}