So I'm making a bitmask class that stores a reference to an std::byte as a member and the index of the individual bit to allow accessing the value of that bit and also assigning to that bit. I also want it to be possible for the value of the std::byte passed to optionally be a const, and if it is a const, I want the class itself to be considered a const or at least make sure operations that may change the underlying value of the std::byte (such as assignment) do not work. However I don't see a way to implement it without copypasting code which I consider to be too complicated. Is there an easier way to get around this? This is my current code for the bitmask class:
class bitmask
{
public:
bitmask(std::byte &chunk, std::uint_fast8_t index) noexcept
: _chunk(chunk), _index(index){};
bitmask(bitmask const &source) = default;
operator bool() const noexcept
{
return static_cast<bool>((_chunk >> (7 - _index)) & std::byte{1});
}
bitmask &operator=(bool val) noexcept
{
_chunk = ((_chunk & ~(std::byte{1} << (7 - _index))) |
(std::byte{val} << (7 - _index)));
return *this;
}
private:
std::byte &_chunk;
std::uint_fast8_t const _index;
};
What I want is to basically make a variant of it where chunk is a const reference and the assignment operator doesn't exist, without copy-pasting existing code to avoid reptition.
PS: I don't mind using any C++ standard, including C++20, as long as it solves the problem elegantly.
One option is to turn bitmask into a template and use SFINAE + type traits to alter the behavior:
// vvv defaults to non-const, change if desired
template<typename Chunk = std::byte>
class bitmask
{
static_assert(std::is_same_v<std::remove_const_t<Chunk>, std::byte>);
public:
bitmask(Chunk &chunk, std::uint_fast8_t index) noexcept
: _chunk(chunk), _index(index){};
bitmask(bitmask const &source) = default;
operator bool() const noexcept
{
return static_cast<bool>((_chunk >> (7 - _index)) & std::byte{1});
}
template<bool Enable = !std::is_const_v<Chunk>, typename = std::enable_if_t<Enable>>
bitmask &operator=(bool val) noexcept
{
_chunk = ((_chunk & ~(std::byte{1} << (7 - _index))) |
(std::byte{val} << (7 - _index)));
return *this;
}
private:
Chunk &_chunk;
std::uint_fast8_t const _index;
};
When using C++17 or newer, template arguments need not be supplied manually as class template argument deduction will infer Chunk based on the argument passed to bitmask's constructor. Earlier versions of C++ can use a make_bitmask factory + type aliases to accomplish similar aesthetics, though unfortunately the const and non-const variants will necessarily have to be spelled out differently.
So, despite there being some really nice answers here, I didn't find any of them particularly elegant, so I decided to delve deeper and solve my own problem. Note that this solution isn't entirely mine, and was originally inspired by #ildjarn 's answer, so props to them as well.
This is how I ended up solving my problem
// Class to mask reference to individual bit
template <bool is_const = false>
class bitmask
{
public:
using ChunkType = std::conditional_t<is_const, std::byte const, std::byte>;
bitmask(ChunkType &chunk, std::uint_fast8_t index) noexcept
: _chunk(chunk), _index(index){};
bitmask(bitmask const &source) = default;
operator bool() const noexcept
{
return static_cast<bool>((_chunk >> (7 - _index)) & std::byte{1});
}
template <typename = std::enable_if_t<!is_const>>
bitmask &operator=(bool val) noexcept
{
_chunk = ((_chunk & ~(std::byte{1} << (7 - _index))) |
(std::byte{val} << (7 - _index)));
return *this;
}
private:
ChunkType &_chunk;
std::uint_fast8_t const _index;
};
bitmask(std::byte &, std::uint_fast8_t)->bitmask<false>;
bitmask(std::byte const &, std::uint_fast8_t)->bitmask<true>;
So basically, the class is a template now which takes a boolean value depending on whether the byte referenced to is a const or not, and I also added template argument deduction hints for the constructor so the constness is automatically deduced. I also made operator= only work if is_const is false.
This is what pointers allow. Either completely constant or completely variable. So, a true-false statement could always be made.A template class that deduces of being constant or not as well.
template<class T>
class overload {
public:
overload(T t): t(t) {
}
~overload() {}
T get() {
if(std::is_const<T>::value)
clog <<"const\t " <<t <<endl;
else if(! std::is_const<T>::value)
clog <<"variable\t " <<t <<endl;
return this->t;
}
T set(T t) {
this->t= t;
}
private:
T t;
};
class test {
public:
test(const int * const _t) : _t(_t) {}
test(int *t) : t(t), _t(NULL) {}
~test() {}
int get() { return *(this->t); }
void set(int *t) { this->t= t; }
const int * const _get() { return (this->_t); }
int __get( ) {
return (_t==NULL)?*t:*_t;
}
//void _set(const int * const _t) { this->_t= _t; }
private:
int *t;
const int *const _t;
};
int main(int argc, char*argv[]) {
int n;
const int m= 99;
n= 100;
overload<int> o(n);
overload<const int> _o(m);
::cout <<o.get() <<endl;
::cout <<_o.get() <<endl;
test t(&n), _t(&m);
::cout <<t.get() <<"\t" <<*_t._get() <<"\t" <<t.__get() <<"\t" <<_t.__get() <<endl;
return 0;
}
Related
Suppose I have the following very simple class:
class A
{
public:
static constexpr A make() { return A{}; }
constexpr A() : _v(0) {}
constexpr A& setV(int v) { _v = v; return *this; }
private:
int _v;
};
If I try to use it as follows:
int main()
{
volatile A a1;
a1.setV(10);
//OR
//The optimizer will optimize this chain of constexpr calls into a single "store" instruction
a1 = A::make().setV(10); //More chaining here
return 0;
}
The code will not compile.
I understand why this is true based upon: Defining volatile class object
I know that the solution would be to add an additional method like so:
class A
{
public:
constexpr A() : _v(0) {}
volatile A& setV(int v) volatile { _v = v; return *this; }
constepxr A& setV(int v) { _v = v; return *this; }
private:
int _v;
};
As an aside, I am aware that returning the volatile reference will issue a warning if it is not used.
My question is, is there any way I can avoid code duplication in this case? Both implementations of setV will always be the same. Thus, if I add/change more methods, I have to maintain them both which could get messy if they aren't so trivial. The only difference is one of type qualifiers...
Since there have been some mentions of this in the comments, I thought I would note that I need volatile here because I am attempting to eventually implement "class overlay" for hardware peripheral register access on an embedded system.
In C++23, you can use an explicit object parameter (also known as deducing this) for this purpose:
class A
{
public:
A() : _v(0) {}
template <class Self>
constexpr auto&& setV(this Self&& self, int v) {
self._v = v; return self;
}
private:
int _v;
};
Unfortunately, as of this writing the only compiler that supports this is the latest version of Microsoft Visual C++.
I came up with one possible solution. It's dubious whether it's less verbose than what I had before, but at least I don't have to duplicate the body of the method. In fact, it's similar (in my mind) to the proposed C++23 answer by #ComicSansMS.
class A
{
public:
constexpr A() : _v(0) {}
template <typename T>
static constexpr void setV(T& dest, int src) { dest = src; }
volatile A& setV(int v) volatile { setV(_v, v); return *this; }
constepxr A& setV(int v) { setV(_v, v); return *this; }
private:
int _v;
};
T will be deduced as either int& or volatile int& depending on the context. Since its declare constexpr/inline, the compiler/optimizer still boils it down to a few assembly instructions.
How to solve std::map default value for move-only types? It seems like the problem is who owns the object
If the value exists, the map stays owner, and a T const& must be returned
If the value does not exits, the caller will be the owner, and a T (move-constructed from the default value) must be returned.
But the return-type of the function must be the same regardless of where the return value came from. Thus it is impossible to take the default value from a temporary. Am I correct?
You could use std::shared_ptr but that would be cheating.
This can be achieved with a proxy object.
template <typename T>
class PossiblyOwner
{
public:
struct Reference {};
PossiblyOwner(const PossiblyOwner & other)
: m_own(other.m_own),
m_ref(m_own.has_value() ? m_own.value() : other.m_ref)
{}
PossiblyOwner(PossiblyOwner && other)
: m_own(std::move(other.m_own)),
m_ref(m_own.has_value() ? m_own.value() : other.m_ref)
{}
PossiblyOwner(T && val) : m_own(std::move(val)), m_ref(m_own.value()) {}
PossiblyOwner(const T & val) : m_own(val), m_ref(m_own.value()) {}
PossiblyOwner(Reference, const T & val) : m_ref(val) {}
const T& value () const { return m_ref; }
operator const T& () const { return m_ref; }
// convenience operators, possibly also define ->, +, etc.
// but they are not strictly needed
auto operator *() const { return *m_ref; }
private:
std::optional<T> m_own;
const T & m_ref;
};
// Not strictly required
template <typename T>
std::ostream & operator<<(std::ostream & out,
const PossiblyOwner<T> & value)
{
return out << value.value();
}
template <typename Container, typename Key, typename ...DefaultArgs>
auto GetOrDefault(const Container & container, const Key & key,
DefaultArgs ...defaultArgs)
-> PossiblyOwner<decltype(container.find(key)->second)>
{
auto it = container.find(key);
using value_type = decltype(it->second);
using ret_type = PossiblyOwner<value_type>;
if (it == container.end())
return {value_type(std::forward<DefaultArgs>(defaultArgs)...)};
else
return {typename ret_type::Reference{}, it->second};
}
Then the usage can be:
int main()
{
std::map<int, std::unique_ptr<std::string>> mapping;
mapping.emplace(1, std::make_unique<std::string>("one"));
mapping.emplace(2, std::make_unique<std::string>("two"));
mapping.emplace(3, std::make_unique<std::string>("three"));
std::cout << *GetOrDefault(mapping, 0,
std::make_unique<std::string>("zero")) << "\n";
std::cout << *GetOrDefault(mapping, 1,
std::make_unique<std::string>("one1")) << "\n";
std::cout << *GetOrDefault(mapping, 3,
new std::string("three1")) << "\n";
}
Edit
I have noticed that the default copy constructor of PossiblyOwner<T> causes undefined behavior, so I had to define a non-default copy and move constructors.
Suppose I have a class Option:
template<typename T>
class Option {
public:
Option() noexcept
{}
Option(T val) noexcept : val_(std::make_shared<T>(std::move(val)))
{}
const T & get() const
{
if (val_ == nullptr) {
throw std::out_of_range("get on empty Option");
}
return *val_;
}
const T & getOrElse(const T &x) const
{
return val_ == nullptr ? x : *val_;
}
private:
std::shared_ptr<T> val_;
};
The argument passed to Option::getOrElse is the default value to return when this Option is empty:
Option<int> x; // empty
int y = 123;
x.getOrElse(y); // == 123
However, I think the following code is not safe:
Option<int> x;
x.getOrElse(123); // reference to temporary variable!
A safer way would be to return by value from Option::getOrElse, but that would be wasteful when the Option is non-empty. Can I work around this somehow?
UPDATE: I'm thinking about perhaps overloading on the argument type (lvalue/rvalue) of getOrElse, but haven't figured out exactly how to do so.
UPDATE 2: Maybe this?
T getOrElse(T &&x) const { ... }
const T & getOrElse(const T &x) const { ... }
But I think this might be ambiguous because both lvalue and rvalue arguments fit the second version.
However, I think the following code is not safe:
Option<int> x;
x.getOrElse(123); // reference to temporary variable!
You are correct. This is why std::optional::value_or() returns a T and not a T& or T const&. As per the rationale in N3672:
It has been argued that the function should return by constant reference rather than value, which would avoid copy overhead in certain situations:
void observe(const X& x);
optional<X> ox { /* ... */ };
observe( ox.value_or(X{args}) ); // unnecessary copy
However, the benefit of the function value_or is only visible when the optional object is provided as a temporary (without the name); otherwise, a ternary operator is equally useful:
optional<X> ox { /* ... */ };
observe(ox ? *ok : X{args}); // no copy
Also, returning by reference would be likely to render a dangling reference, in case the optional object is disengaged, because the second argument is typically a temporary:
optional<X> ox {nullopt};
auto&& x = ox.value_or(X{args});
cout << x; // x is dangling!
I suggest you follow the same guidelines. If you really need to avoid the copy, use a ternary. This is safe and copyless:
Optional<int> ox = ...;
const int& val = ox ? *ox : 123;
If you really don't, or the Optional is an rvalue anyway, getOrElse() is more concise.
Since users of your class can expect the reference returned from Option::get() to be valid only as along as the the particular instance of the Option object's lifetime, you could reasonably make the same expectation for what is returned from Option::getOrElse().
In that case it might be an acceptable overhead for the object to maintain a collection of things that it needs to keep alive for the client:
#include <list>
#include <memory>
#include <iostream>
template<typename T>
class Option {
public:
Option() noexcept
{}
Option(T val) noexcept : val_(std::make_shared<T>(std::move(val)))
{}
const T & get() const
{
if (val_ == nullptr) {
throw std::out_of_range("get on empty Option");
}
return *val_;
}
const T & getOrElse(const T &x) const
{
if (val_ == nullptr) {
std::cout << "storing const T &\n";
elses_.push_front(x);
return elses_.front();
}
return *val_;
}
const T & getOrElse(T &&x) const
{
if (val_ == nullptr) {
std::cout << "storing T && by move\n";
elses_.push_front(std::move(x));
return elses_.front();
}
return *val_;
}
private:
std::shared_ptr<T> val_;
mutable std::list<T> elses_;
};
int main()
{
Option<int> x; // empty
int y = 123;
auto rx = x.getOrElse(y); // == 123
auto & rxx = x.getOrElse(42);
std::cout << "rx = " << rx << "\n";
std::cout << "rxx = " << rxx << "\n";
}
The references returned by Option::getOrElse() will be valid for as long as the reference returned from Option::get() would be. Of course, this also means that Option::getOrElse() can throw an exception.
As a small improvement, if the T type can be used as keys for an associative container you could use one of those instead of a std::list and easily avoid storing duplicates.
I'd rather return by reference and let the caller decide, whether he wants to store a reference to or a copy of the returned value.
Can I suggest to re-design this class?
It has a default ctor which can leave the val_ to be nullptr, but it has a get() at the same time which may throw exception because of dereference (*). It also designed to save T in shared_prt but return it as reference.
Let the client to know it's null:
template<typename T>
class Option {
public:
Option() noexcept
{}
Option(T val) noexcept : val_(std::make_shared<T>(std::move(val)))
{}
const T & get() const
{
return *val_;
}
bool IsNull() const
{
return val_ == nullptr;
}
private:
std::shared_ptr<T> val_;
};
The client code changed from:
Option option;
const T & ref = option.getOrElse(123);
to be:
Option option;
const T & ref = option.IsNull() ? 123 : option.get();
Why I delete the: if (val_ == nullptr) {
Let's make make_shared<> clear:
return a valid pointer, or
throw bad_alloc exception; it does not return null
So IsNull() is also useless, it should be like:
template<typename T>
class Option {
public:
Option(T val) noexcept : val_(std::make_shared<T>(std::move(val)))
{}
const T & get() const
{
return *val_;
}
private:
std::shared_ptr<T> val_;
};
Why to use shared_ptr? option objects can be move or copied several times? or else I prefer to design it like:
template<typename T>
class Option {
public:
Option(T val) noexcept : val_(std::move(val))
{}
const T & get() const
{
return val_;
}
private:
T val_;
};
We use boost - so using that library should be fine.
But I've never managed to wrap my head around creating a set of templates which give you the right specialization for a whole class of data types, as opposed to specializing for a single data type (which I know how to do).
Let me go for an example to try to bring this down to earth. I want to have a set of classes which can be used as:
Initialized<T> t;
Where T is either a simple basic type, a PODS, or an array. It cannot be a class, for a class is expected to have its own constructor, and overwriting its raw memory is a terrible idea.
Initialized should basically memset(&t, 0, sizeof(t)); It makes it easier to ensure that runtime code is not different from debug code when dealing with legacy structs.
Initialized where SDT = simple data type, should simply create a struct which wrappers the underlying SDT and uses the compilers t() to generate the compiler defined default constructor for that type (it could amount to a memset as well, though it seems more elegant to simply result in t().
Here's a stab at it, using Initialized<> for PODs, and Initialised<> for SDTs:
// zeroed out PODS (not array)
// usage: Initialized<RECT> r;
template <typename T>
struct Initialized : public T
{
// ensure that we aren't trying to overwrite a non-trivial class
BOOST_STATIC_ASSERT((boost::is_POD<T>::value));
// publish our underlying data type
typedef T DataType;
// default (initialized) ctor
Initialized() { Reset(); }
// reset
void Reset() { Zero((T&)(*this)); }
// auto-conversion ctor
template <typename OtherType> Initialized(const OtherType & t) : T(t) { }
// auto-conversion assignment
template <typename OtherType> Initialized<DataType> & operator = (const OtherType & t) { *this = t; }
};
And for SDTs:
// Initialised for simple data types - results in compiler generated default ctor
template <typename T>
struct Initialised
{
// default valued construction
Initialised() : m_value() { }
// implicit valued construction (auto-conversion)
template <typename U> Initialised(const U & rhs) : m_value(rhs) { }
// assignment
template <typename U> T & operator = (const U & rhs) { if ((void*)&m_value != (void*)&rhs) m_value = rhs; return *this; }
// implicit conversion to the underlying type
operator T & () { return m_value; }
operator const T & () const { return m_value; }
// the data
T m_value;
};
I have specialized Initialised for T*, to provide natural pointer behaviors. And I have an InitializedArray<> for arrays, which takes both the element type and array-size as template arguments. But again, I have to use template name to distinguish - I don't grok MPL well enough to provide a single template that results in the correct specialization at compile time all from a single name (Initialized<>, ideally).
I would love also to be able to provide an overloaded Initialized<typename T, T init_value> as well, so that for non-scalar values the user could define the default initialization value (or memset value)
I apologize for asking something that may take a bit of effort to answer. This seems to be a hurdle that I haven't been able to overcome in my own MPL reading on my own, but perhaps with some of your help I may be able to nail this functionality down!
Based on Uncle Ben's answer(s) below, I tried the following:
// containment implementation
template <typename T, bool bIsInheritable = false>
struct InitializedImpl
{
// publish our underlying data type
typedef T DataType;
// auto-zero construction
InitializedImpl() : m_value() { }
// auto-conversion constructor
template <typename U> InitializedImpl(const U & rhs) : m_value(rhs) { }
// auto-conversion assignment
template <typename U> T & operator = (const U & rhs) { if ((void*)&m_value != (void*)&rhs) m_value = rhs; return *this; }
// implicit conversion to the underlying type
operator T & () { return m_value; }
operator const T & () const { return m_value; }
// the data
T m_value;
};
// inheritance implementation
template <typename T>
struct InitializedImpl<T,true> : public T
{
// publish our underlying data type
typedef T DataType;
// auto-zero ctor
InitializedImpl() : T() { }
// auto-conversion ctor
template <typename OtherType> InitializedImpl(const OtherType & t) : T(t) { }
// auto-conversion assignment
template <typename OtherType> InitializedImpl<DataType> & operator = (const OtherType & t) { *this = t; }
};
// attempt to use type-traits to select the correct implementation for T
template <typename T>
struct Initialized : public InitializedImpl<T, boost::is_class<T>::value>
{
// publish our underlying data type
typedef T DataType;
};
And then tried a couple of usage tests.
int main()
{
Initialized<int> i;
ASSERT(i == 0);
i = 9; // <- ERROR
}
This results in an error: *binary '=' : no operator found which takes a right-hand operand of type 'InitializedImpl ' (or there is no acceptable conversion)
Whereas if I directly instantiate the correct base type (instead of a derived type):
int main()
{
InitializedImpl<int,false> i;
ASSERT(i == 0);
i = 9; // <- OK
}
Now I can use i as any old int. Which is what I want!
The exact same problems arise if I try to do the same for structs:
int main()
{
Initialized<RECT> r;
ASSERT(r.left == 0); // <- it does let me access r's members correctly! :)
RECT r1;
r = r1; // <- ERROR
InitializedImpl<RECT,true> r2;
r2 = r1; // OK
}
So, as you can see, I need some way to tell the compiler to promote an Initialized to act like a true T.
If C++ let me inherit from basic types, I could just use the inheritance technique and all would be well.
Or if I had some way to tell the compiler to extrapolate all methods in parent to child, so that anything valid on parent was valid on child, I'd be okay.
Or if I could use MPL or type-traits to typedef instead of inherit what I need, then there would be no child class, and no propagation issue.
Ideas?!...
Initialized should basically
memset(&t, 0, sizeof(t)); It makes it
easier to ensure that runtime code is
not different from debug code when
dealing with legacy structs.
I don't think you should need memset, because you can zero-initialize PODs just as you can explicitly invoke the default constructor of non-PODs. (unless I'm terribly mistaken).
#include <cassert>
struct X {int a, b; };
template <typename T>
struct Initialized
{
T t;
// default (initialized) ctor
Initialized(): t() { }
};
template <typename T>
struct WithInheritance: public T
{
// default (initialized) ctor
WithInheritance(): T() { }
};
int main()
{
Initialized<X> a;
assert(a.t.a == 0 && a.t.b == 0);
//it would probably be more reasonable not to support arrays,
//and use boost::array / std::tr1::array instead
Initialized<int[2]> b;
assert(b.t[0] == 0 && b.t[1] == 0);
WithInheritance<X> c;
assert(c.a == 0 && c.b == 0);
}
In your quest to determine the pod-ness of a type, you might also take into account this note from boost::is_pod reference:
Without some (as yet unspecified) help
from the compiler, is_pod will never
report that a class or struct is a
POD; this is always safe, if possibly
sub-optimal. Currently (May 2005) only
MWCW 9 and Visual C++ 8 have the
necessary compiler intrinsics.
(I think boost::type_traits are making it into the standard library in C++0x, and in such a case it would be reasonable to expect an is_pod that actually works.)
But if you want to specialize based on a condition, you can introduce a bool parameter. E.g something like this:
#include <limits>
#include <cstdio>
template <class T, bool b>
struct SignedUnsignedAux
{
void foo() const { puts("unsigned"); }
};
template <class T>
struct SignedUnsignedAux<T, true>
{
void foo() const { puts("signed"); }
};
//using a more reliable condition for an example
template <class T>
struct SignedUnsigned: SignedUnsignedAux<T, std::numeric_limits<T>::is_signed > {};
int main()
{
SignedUnsigned<int> i;
SignedUnsigned<unsigned char> uc;
i.foo();
uc.foo();
}
Here's also something that works sort of like you might be imagining (compiles at least with MinGW 4.4 and VC++ 2005 - the latter also nicely produces a warning that the array will be zero-initialized! :)).
This uses a default boolean argument which you probably shouldn't ever specify yourself.
#include <boost/type_traits.hpp>
#include <iostream>
template <class T, bool B = boost::is_scalar<T>::value>
struct Initialized
{
T value;
Initialized(const T& value = T()): value(value) {}
operator T& () { return value; }
operator const T& () const { return value; }
};
template <class T>
struct Initialized<T, false>: public T
{
Initialized(const T& value = T()): T(value) {}
};
template <class T, size_t N>
struct Initialized<T[N], false>
{
T array[N];
Initialized(): array() {}
operator T* () { return array; }
operator const T* () const { return array; }
};
//some code to exercise it
struct X
{
void foo() const { std::cout << "X::foo()" << '\n'; }
};
void print_array(const int* p, size_t size)
{
for (size_t i = 0; i != size; ++i) {
std::cout << p[i] << ' ';
}
std::cout << '\n';
}
template <class T>
void add_one(T* p, size_t size)
{
for (size_t i = 0; i != size; ++i) {
p[i] += T(1);
}
}
int main()
{
Initialized<int> a, b = 10;
a = b + 20;
std::cout << a << '\n';
Initialized<X> x;
x.foo();
Initialized<int[10]> arr /*= {1, 2, 3, 4, 5}*/; //but array initializer will be unavailable
arr[6] = 42;
add_one<int>(arr, 10); //but template type deduction fails
print_array(arr, 10);
}
However, Initialized will probably never be as good as the real thing. One short-coming is shown in the test code: it can interfere with template type deduction. Also, for arrays you'll have a choice: if you want to zero-initialize it with the constructor, then you can't have non-default array initialization.
If the usage is that you are going to track down all uninitialized variables and wrap them into Initialized, I'm not quite sure why you won't just initialized them yourself.
Also, for tracking down uninitialized variables, perhaps compiler warnings can help a lot.
I know it doesn't answer your question, but I thought POD structures were always zero-initialised anyway.
Since I was able to use UncleBen's answers to create a comprehensive solution (as good as I think it gets at this point in C++), I wanted to share it, below:
Feel free to use it, but I make no guarantees whatsoever about its worthiness for any use whatsoever, etc., etc., be an adult and take responsibility for your own damn actions, blah, blah:
//////////////////////////////////////////////////////////////
// Raw Memory Initialization Helpers
//
// Provides:
// Zero(x) where x is any type, and is completely overwritten by null bytes (0).
// Initialized<T> x; where T is any legacy type, and it is completely null'd before use.
//
// History:
//
// User UncleBen of stackoverflow.com and I tried to come up with
// an improved, integrated approach to Initialized<>
// http://stackoverflow.com/questions/2238197/how-do-i-specialize-a-templated-class-for-data-type-classification
//
// In the end, there are simply some limitations to using this
// approach, which makes it... limited.
//
// For the time being, I have integrated them as best I can
// However, it is best to simply use this feature
// for legacy structs and not much else.
//
// So I recommend stacked based usage for legacy structs in particular:
// Initialized<BITMAP> bm;
//
// And perhaps some very limited use legacy arrays:
// Initialized<TCHAR[MAX_PATH]> filename;
//
// But I would discourage their use for member variables:
// Initialized<size_t> m_cbLength;
// ...as this can defeat template type deduction for such types
// (its not a size_t, but an Initialized<size_t> - different types!)
//
//////////////////////////////////////////////////////////////
#pragma once
// boost
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
// zero the memory space of a given PODS or native array
template <typename T>
void Zero(T & object, int zero_value = 0)
{
// ensure that we aren't trying to overwrite a non-trivial class
BOOST_STATIC_ASSERT((boost::is_POD<T>::value));
// make zeroing out a raw pointer illegal
BOOST_STATIC_ASSERT(!(boost::is_pointer<T>::value));
::memset(&object, zero_value, sizeof(object));
}
// version for simple arrays
template <typename T, size_t N>
void Zero(T (&object)[N], int zero_value = 0)
{
// ensure that we aren't trying to overwrite a non-trivial class
BOOST_STATIC_ASSERT((boost::is_POD<T>::value));
::memset(&object, zero_value, sizeof(object));
}
// version for dynamically allocated memory
template <typename T>
void Zero(T * object, size_t size, int zero_value = 0)
{
// ensure that we aren't trying to overwrite a non-trivial class
BOOST_STATIC_ASSERT((boost::is_POD<T>::value));
::memset(object, zero_value, size);
}
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Initialized for non-inheritable types
// usage: Initialized<int> i;
template <typename T, bool SCALAR = boost::is_scalar<T>::value>
struct Initialized
{
// ensure that we aren't trying to overwrite a non-trivial class
BOOST_STATIC_ASSERT((boost::is_scalar<T>::value));
// the data
T m_value;
// default valued construction
Initialized() : m_value() { }
// implicit valued construction (auto-conversion)
template <typename U> Initialized(const U & rhs) : m_value(rhs) { }
// assignment
template <typename U> T & operator = (const U & rhs) { if ((void*)&m_value != (void*)&rhs) m_value = rhs; return *this; }
// implicit conversion to the underlying type
operator T & () { return m_value; }
operator const T & () const { return m_value; }
// zero method for this type
void _zero() { m_value = T(); }
};
//////////////////////////////////////////////////////////////////////////
// Initialized for inheritable types (e.g. structs)
// usage: Initialized<RECT> r;
template <typename T>
struct Initialized<T, false> : public T
{
// ensure that we aren't trying to overwrite a non-trivial class
BOOST_STATIC_ASSERT((boost::is_POD<T>::value));
// default ctor
Initialized() : T() { }
// auto-conversion ctor
template <typename OtherType> Initialized(const OtherType & value) : T(value) { }
// auto-conversion assignment
template <typename OtherType> Initialized & operator = (const OtherType & value) { *this = value; }
// zero method for this type
void _zero() { Zero((T&)(*this)); }
};
//////////////////////////////////////////////////////////////////////////
// Initialized arrays of simple types
// usage: Initialized<char, MAXFILENAME> szFilename;
template <typename T, size_t N>
struct Initialized<T[N],false>
{
// ensure that we aren't trying to overwrite a non-trivial class
BOOST_STATIC_ASSERT((boost::is_POD<T>::value));
// internal data
T m_array[N];
// default ctor
//Initialized() : m_array() { } // Generates a warning about new behavior. Its okay, but might as well not produce a warning.
Initialized() { Zero(m_array); }
// array access
operator T * () { return m_array; }
operator const T * () const { return m_array; }
// NOTE: All of the following techniques leads to ambiguity.
// Sadly, allowing the type to convert to ArrayType&, which IMO should
// make it fully "the same as it was without this wrapper" instead causes
// massive confusion for the compiler (it doesn't understand IA + offset, IA[offset], etc.)
// So in the end, the only thing that truly gives the most bang for the buck is T * conversion.
// This means that we cannot really use this for <char> very well, but that's a fairly small loss
// (there are lots of ways of handling character strings already)
// // automatic conversions
// operator ArrayType& () { return m_array; }
// operator const ArrayType& () const { return m_array; }
//
// T * operator + (long offset) { return m_array + offset; }
// const T * operator + (long offset) const { return m_array + offset; }
//
// T & operator [] (long offset) { return m_array[offset]; }
// const T & operator [] (long offset) const { return m_array[offset]; }
// metadata
size_t GetCapacity() const { return N; }
// zero method for this type
void _zero() { Zero(m_array); }
};
//////////////////////////////////////////////////////////////////////////
// Initialized for pointers to simple types
// usage: Initialized<char*> p;
// Please use a real smart pointer (such as std::auto_ptr or boost::shared_ptr)
// instead of this template whenever possible. This is really a stop-gap for legacy
// code, not a comprehensive solution.
template <typename T>
struct Initialized<T*, true>
{
// the pointer
T * m_pointer;
// default valued construction
Initialized() : m_pointer(NULL) { }
// valued construction (auto-conversion)
template <typename U> Initialized(const U * rhs) : m_pointer(rhs) { }
// assignment
template <typename U> T * & operator = (U * rhs) { if (m_pointer != rhs) m_pointer = rhs; return *this; }
template <typename U> T * & operator = (const U * rhs) { if (m_pointer != rhs) m_pointer = rhs; return *this; }
// implicit conversion to underlying type
operator T * & () { return m_pointer; }
operator const T * & () const { return m_pointer; }
// pointer semantics
const T * operator -> () const { return m_pointer; }
T * operator -> () { return m_pointer; }
const T & operator * () const { return *m_pointer; }
T & operator * () { return *m_pointer; }
// allow null assignment
private:
class Dummy {};
public:
// amazingly, this appears to work. The compiler finds that Initialized<T*> p = NULL to match the following definition
T * & operator = (Dummy * value) { m_pointer = NULL; ASSERT(value == NULL); return *this; }
// zero method for this type
void _zero() { m_pointer = NULL; }
};
//////////////////////////////////////////////////////////////////////////
// Uninitialized<T> requires that you explicitly initialize it when you delcare it (or in the owner object's ctor)
// it has no default ctor - so you *must* supply an initial value.
template <typename T>
struct Uninitialized
{
// valued initialization
Uninitialized(T initial_value) : m_value(initial_value) { }
// valued initialization from convertible types
template <typename U> Uninitialized(const U & initial_value) : m_value(initial_value) { }
// assignment
template <typename U> T & operator = (const U & rhs) { if (&m_value != &rhs) m_value = rhs; return *this; }
// implicit conversion to underlying type
operator T & () { return m_value; }
operator const T & () const { return m_value; }
// the data
T m_value;
};
//////////////////////////////////////////////////////////////////////////
// Zero() overload for Initialized<>
//////////////////////////////////////////////////////////////////////////
// version for Initialized<T>
template <typename T, bool B>
void Zero(Initialized<T,B> & object)
{
object._zero();
}
I need to create a generic object carrier class. I came up with something simple like
template<typename T>
class ObjectCarrier
{
public:
const T& item() const
{
return item_;
}
void setItem(T& item)
{
item_ = item;
}
private:
T item_;
};
This works well when T has got a default constructor (parameterless). Things gets complicated when T has parameterized constructors. So I rewrote the class like
template<typename T>
class ObjectCarrier
{
public:
const T& item() const
{
return *item_;
}
void setItem(T& item)
{
item_ = new T ( item );
}
private:
T* item_;
};
Changed the item_ variable to T* and created a new instance using the copy constructor of T. Again this worked well until T is a pointer type. I mean ObjectCarrier<Foo*> won't work.
I am wondering how can I design this class so that it works for almost all kind of types. I think I may need to create a traits type specialized for pointers. But unfortunately, I am not able to make that work.
Any help would be great.
The above approaches are way way too complicated. Keep it simple, and just solve the constructor arg problem by using template constructors. Don't use pointers, they will create object lifetime and copying headaches.
Here's an implementation I use a lot. The template constructors will forward arguments for things directly on to the nested object which is convenient. The operator T& values let you pass carrier<T> to functions that take a type T, without expensive copying. You can wrap objects that take up to two arguments with this code.
/* A wrapper of type T */
template <typename T>
struct carrier {
carrier() {}
template <typename A1> carrier(const A1& a1) : value(a1) {}
template <typename A1, typename A2> carrier(const A1& a1, const A2& a2) : value(a1, a2) {}
operator T&() { return value; }
operator const T&() const { return value; }
T value;
};
You can use it like this:
const carrier<point> p1(10,10); // make p1 const to stop people changing it
showPoint(p1); // calls a function that expects a point,
showPoint(p1.value); // access the point directly
You can use template specialization for the T* type and rewrite the methods to suite pointers. You can do something like:
template<typename T>
class ObjectCarrier<T*>
{
public:
const T* item() const
{
return item_;
}
void setItem(T* item)
{
item_ = item;
}
private:
T* item_;
};
There is a design patern that is possibly relevant to this - Memento.
A bit off topic, but bear in mind that as soon as you start newing objects up inside your class, you'll need a way to manage the memory. I'd suggest using an std::auto_ptr at the least. You'll also need to provide a copy constructor and an assignment operator, when using std::auto_ptr.
It might be possible to hold the object by value and still defer its construction with the use of placement new and something like the following:
#include <iostream>
#include <cassert>
template <class T>
class ObjectCarrier
{
public:
ObjectCarrier(): ref(0) {}
ObjectCarrier(const ObjectCarrier& other): ref(0)
{
set_data(other.ref);
}
~ObjectCarrier()
{
clear();
}
const ObjectCarrier& operator = (const ObjectCarrier& other)
{
if (other.empty())
clear();
else
set_data(other.ref);
return *this;
}
void set(const T& value)
{
set_value(value);
}
const T& get() const
{
assert(!empty() && "No object being carried");
return *ref;
}
bool empty() const
{
return ref == 0;
}
void clear()
{
if (!empty()) {
ref->~T();
ref = 0;
}
}
private:
char data[sizeof(T)];
T* ref;
void set_value(const T& value)
{
if (!empty()) {
*ref = value;
}
else {
ref = new (data) T(value);
}
}
void set_data(const T* value)
{
if (value) {
set_value(*value);
}
}
};
int main()
{
ObjectCarrier<int> i;
ObjectCarrier<int> j(i);
i = j;
i.set(10);
std::cout << i.get() << '\n';
j = i;
i.set(20);
std::cout << i.get() << ' ' << j.get() << ' ' << ObjectCarrier<int>(i).get() << '\n';
}
However, I would somewhat question the usefulness of this class. Perhaps the only purpose it could have, would be to act as Boost.Optional.
But if you don't want the class to be able to not hold a value, just give it a parametrized constructor:
template<typename T>
class ObjectCarrier
{
public:
ObjectCarrier(const T& value = T()):
item_(value)
{
}
const T& item() const
{
return item_;
}
void setItem(T& item)
{
item_ = item;
}
private:
T item_;
};
(It's just that this class seems rather useless, unless perhaps as a facade for code that expects variables to have item and setItem methods, rather than, say, an assignment operator.)
boost::optional does something very similar to this (also boost::any, but nevermind).
You can check out how its implemented at: http://cplusplus.co.il/2009/12/04/boost-optional-and-its-internals/ and don't worry - it's pretty straightforward.