We cannot make operator++(int) virtual directly because of the return type problem. The usual advice is to apply the curiously named Curiously Recurring Template Pattern, which I implemented to the best of my modest understanding as follows:
// abstract numeric type
template <typename T>
class A {
public:
virtual T& operator++() = 0;
virtual T get() const = 0;
virtual string toString() const = 0;
virtual T operator++(int) {
T old(this->get());
++*this; // calls operator++() from derived class
return old;
}
friend ostream& operator<<(ostream& os, const A& a) {
return os << a.toString();
}
virtual ~A() = 0;
};
// signed numeric type
class S : public A<S> {
public:
S(long l) : m_l(l) {}
virtual S get() const { return m_l; }
virtual string toString() const { return to_string(m_l); }
virtual S& operator++() { // no wrapping, caps at LONG_MAX
if (m_l < LONG_MAX)
++m_l;
return *this;
}
private:
long m_l;
};
// unsigned numeric type
class U : public A<U> {
public:
U(unsigned long ul) : m_ul(ul) {}
virtual U get() const { return m_ul; }
virtual string toString() const { return to_string(m_ul); }
virtual U& operator++() { // no wrapping, caps at ULONG_MAX
if (m_ul < ULONG_MAX)
++m_ul;
return *this;
}
private:
unsigned long m_ul;
};
Lots of code duplication, but at least it allows for constructs like the following to run, which is definitely a start:
template <typename T>
void pinc(A<T>& a) {
cout << a++ << ' ' << a << endl;
}
int main() {
S s(LONG_MAX);
pinc(s);
U u(LONG_MAX);
pinc(u);
return 0;
}
Sadly, it does not help with things like vector<A*>: S and U have no common ancestor. If I derive A from another base class, I also have to move the templated part there and the problem - ha! - goes recursive.
So, any suggestions?
Note to editors: Having learned my lesson, I saved the original this time. :)
I do not think this is possible within C++ type system, here is why:
Consider the following example: Let say we somehow achieve this and have A* a pointer to the base class from which U and S was derived. Then what will be the type of the var = (*a)++;? It could be either U or S depending on what a is pointing to. But compiler need to know return type during compilation because operator++(int) return S and U by-value.
I see the following ways to work around this problem but they all need to change the return types of operator++(int) in hierarchy to make them covariant (see C++ virtual function return type):
Return pointer to a (base) class within your hierarchy
If your types is integer types (like operator++ return char, int, long for different classes) then you can make them all return enclosing type: long int
Instead of returning direct values of your objects (U or S) return some kind of struct that is capable of holding any of these types. (see http://www.boost.org/doc/libs/1_61_0/doc/html/any.html for possible generic way to do this)
Related
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;
}
I have a simple wrapper class for Integer types, defined like so:
class Integer {
public:
Integer() {
}
Integer(const int& value) {
this->value = value;
}
int toInt() const {
return value;
}
operator int() const {
return toInt();
}
private:
int value = 0;
};
What I'd like to do, is pass the class above to a function which has a signature like this:
doSomething(int* value)
If I were to use a normal int, I could simply do:
int value = 5;
doSomething(&value);
However, when using the wrapper class I can't since it would use a pointer to the class instead of the actual underlying value.
I know of the address operator operator&, which I could use to return a pointer to the value, but it would prevent me from getting a pointer to the class itself if I needed to.
So ideally there would be a way that would allow me to use &myclass to get a pointer to the class or the underlying value, depending on what is needed.
Is there such a way?
It seems I was able to solve my own problem.
I took some inspiration from a comment by #Arunmu and the following question: https://stackoverflow.com/a/9569120
By overloading the operator&() (address-of) operator and returning a proxy class object, which has implicit conversion operators to pointers of both the type of my original class and the value it wraps I can use the syntax I needed.
I will provide an example for anyone who encounters the same problem:
class IntegerPointer {
public:
IntegerPointer(int& value, Integer& wrapper) : value(value), wrapper(wrapper) {
}
operator int*() {
return &value;
}
operator Integer*() {
return std::addressof(wrapper);
}
private:
int& value;
Integer& wrapper;
};
class Integer {
public:
Integer() {
}
Integer(const int& value) : value(value) {
}
Integer(const Integer& value) : Integer(value.value) {
}
IntegerPointer operator&() {
return IntegerPointer(value, (*this));
}
protected:
int value;
};
This allows you to use syntax such as:
Integer test = 5;
doSomething(&test);
Where &test can be used as a pointer to the Integer object or as a pointer to the int value it wraps.
Assume I have a class A that I want to store in an unordered_set with custom hasher and comparer. I also have a container class B that stores this set:
class B {
private:
std::unordered_set<A, Hasher, Comparer> set;
};
To make this compile I would have to make B a template class, which I want to avoid, as this would lead to some major refactoring and actually moves this problem just a layer up where I would then have to handle template parameters for B.
Next I tried to make class that specialize the set:
class MySet1 : public std::unordered_set<A, MyHasher1, MyComparer1> {
};
class MySet2 : public std::unordered_set<A, MyHasher2, MyComparer2> {
};
Obviously that doesn't help as I still have no common base class for my set var in class B.
To solve this I moved down the unordered set one level:
class MySet {
public:
// Some abstract functions...
};
class MySet1 : public MySet {
public:
// Implementation of the abstract functions.
private:
std::unordered_set<A, MyHasher1, MyComparer1> set;
};
class MySet2 : public MySet {
public:
// Implementation of the abstract functions.
private:
std::unordered_set<A, MyHasher2, MyComparer2> set;
};
Now I have a common base class (MySet) for class B. But the obvious disadvantages are: code duplication for each set specialization and I would have to imlement custom iterators to make the sets work with the STL. Here's were I stopped and asked myself if there's a better way to accomplish what I actually want: store different unordered_set classes in the same member var without the need to make the owner of that var templated as well.
Main idea
You can happily employ multiple inheritance here.
The main idea is: create a base class tagging your sets and make it a base class for all your sets. Then explicitly instantiate the set class for each template arguments you need, creating an empty class inherited publicly from both the set container and your tagging interface. Then you'll have nothing to add, no code duplication seems to be needed.
Anyway, you'll need to create some (maybe virtual) functions that will work for all template specializations. We'll need to be able to use a single variable in the same context regardless of what it holds. But you can try reduce some code with more using declarations due to inheritance and use implicit type conversion (e.g. if your sets contain numbers only).
#include <set>
class setInterface {
/* Code common for all set template specializations
(you have to have some common interface anyway) */
};
template <typename T> class TSet: public setInterface, std::set<T> {
using std::set<T>::set;
/* more using-declarations or templated versions of some functions
You can use SFINAE here to achieve more magical results,
or use template specializations for specific types. */
};
using intSet = TSet<int>;
using doubleSet = TSet<double>;
class B {
public:
setInterface values;
};
int main () {
B b;
b.values = intSet {1, 2, 3} ;
b.values = doubleSet {1., 2., 3.};
}
PS: thanks go to #Jarod42 for the template using syntax.
A working implementation
The following assumptions have been made:
We will use only the sets with items convertible to long long. We can use void* in general case and add some additional methods for convenience/safety.
We are sane and will never compare iterators of differently typed sets. The results will be unpredictable.
We don't need to check pointers for nullptrs (well, it will bring no more value in my code sample, sure in real world you always need).
The solution is able to iterate over the map using non-const begin/ends and using the new shiny range-based for. See the main; compile and run it (-std=c++14) to see the result.
#include <set>
#include <memory>
#include <iostream>
using common_denominator_type = long long;
class setInterface {
protected:
class iterator_impl;
public:
class iterator {
public:
iterator (iterator_impl* impl) : impl (impl) {}
iterator& operator++ () { ++*impl; return *this; };
bool operator != (const iterator& rhs) const { return *impl != *rhs.impl; };
common_denominator_type operator* () const { return **impl; };
private:
std::shared_ptr <iterator_impl> impl;
};
virtual iterator begin() = 0;
virtual iterator end() = 0;
virtual size_t size() const = 0;
protected:
class iterator_impl {
public:
virtual iterator_impl& operator++ () = 0;
virtual bool operator != (const iterator_impl&) const = 0;
virtual common_denominator_type operator* () const = 0;
virtual void* as_std_set_iterator () = 0;
virtual const void* as_std_set_iterator () const = 0;
};
};
template <typename T> class TSet: public setInterface, std::set<T> {
public:
using std::set<T>::set;
size_t size () const override { return std::set<T>::size(); }
iterator begin () override { return iterator (new TSet<T>::iterator_impl (std::set<T>::begin())); }
iterator end () override { return iterator (new TSet<T>::iterator_impl (std::set<T>::end ())); }
protected:
class iterator_impl: public setInterface::iterator_impl {
public:
using std_it = typename std::set<T>::iterator;
iterator_impl (std_it&& _) : m_real_iterator(std::move (_)) {}
iterator_impl& operator++ () override { ++m_real_iterator; return *this; }
bool operator != (const setInterface::iterator_impl& rhs) const override {
return *reinterpret_cast <const std_it*>(as_std_set_iterator())
!=
*reinterpret_cast <const std_it*>(rhs.as_std_set_iterator());
}
common_denominator_type operator* () const override { return *m_real_iterator; }
void* as_std_set_iterator () override { return &m_real_iterator; }
const void* as_std_set_iterator () const override { return &m_real_iterator; }
private:
std_it m_real_iterator;
};
};
using intSet = TSet<int>;
using longSet = TSet<long>;
class B {
public:
std::shared_ptr <setInterface> values;
};
std::ostream& operator<< (std::ostream& str, B& b) {
str << "[" << b.values->size() << "] [";
for (auto i = b.values->begin(); i != b.values->end(); ++i)
str << *i << " ";
str << "][";
for (auto i : *b.values)
str << i << " ";
return str << "]";
}
int main () {
B b;
b.values.reset (new intSet {1, 2, 3});
std::cout << b << std::endl;
b.values.reset (new longSet {10l, 20l, 30l});
std::cout << b << std::endl;
}
I have the following (very simplified) "container" class:
class container
{
public:
template<typename T> container(const boost::shared_ptr<T> &rhs)
: m_content(rhs) { }
template<typename T>
operator T const & () const
{
return get<T>();
}
template<typename T>
T const & get() const
{
return *boost::any_cast< boost::shared_ptr<T> >(m_content);
}
private:
boost::any m_content;
};
It should store objects in the boost::any container in the form of a shared pointer. If I store some object, say, of the boost::shared_ptr<some_type> type in the container, I would like to get the reference (const some_type&) simply by a user-defined conversion which would allow to do something like this:
boost::shared_ptr<some_type> x(new some_type);
container cx = x;
...
// user-defined conversion
const some_type &y = cx;
// a template conversion using a "getter"
const some_type &y = cx.get<some_type>();
Sometimes, I need to store objects derived from some abstract type and do the same sort of type conversion to the reference of this abstract type, for example, like this:
boost::shared_ptr<some_abstract_type> x(new some_derived_type);
container cx = x;
...
// user-defined conversion
const some_abstract_type &y = cx;
// a template conversion using a "getter"
const some_abstract_type &y = cx.get<some_abstract_type>();
Both the user-defined conversion and the template "getter" work fine with GCC. However, the Intel C++ compiler seems to have a problem with the (user-defined) conversion while the "getter" works.
For example, the following code works with GCC but not with Intel:
#include <iostream>
#include <boost/any.hpp>
#include <boost/shared_ptr.hpp>
class container
{
public:
template<typename T> container(const boost::shared_ptr<T> &rhs)
: m_content(rhs) { }
template<typename T>
operator T const & () const
{
return get<T>();
}
template<typename T>
T const & get() const
{
return *boost::any_cast< boost::shared_ptr<T> >(m_content);
}
private:
boost::any m_content;
};
class base
{
public:
virtual ~base() { }
virtual void f() const = 0;
};
class derived : public base
{
public:
virtual ~derived() { }
virtual void f() const { std::cout << "hello\n"; }
};
void foo(const container &c)
{
const base & a = c;
a.f();
}
int main()
{
boost::shared_ptr<base> a(new derived);
container c = a;
foo(c);
}
With Intel, I get this error:
test.cpp(44): error: no suitable user-defined conversion from "const container" to "const base" exists
const base & a = c;
^
compilation aborted for test.cpp (code 2)
On the other hand, if I replace base with derived in both main() and foo() (or use the "getter" instead of the type conversion in foo()), everything works fine with Intel too. Is it possible to convince the Intel compiler to use the user-defined type conversion to the reference type when T is an abstract class?
Thanks in advance for any ideas.
EDIT: Interestingly, using the type conversion to the pointer type works fine. If I add
template<typename T>
operator T const * () const
{
return &get<T>();
}
to the container class and replace foo() with
void foo(const container &c)
{
const base * a = c;
a->f();
}
then it works also with Intel.
I would return a pointer in the getter:
template<typename T>
T const * get() const {
return boost::any_cast< boost::shared_ptr<T> >(m_content);
}
This avoids the conversion problem, and does not crash immediately if you pass a null pointer to your container.
Example:
void foo(const container &c)
{
const base* a = c.get<base>();
a->f();
}
You could also add a function valid() which checks if there is something in the container:
bool valid() const {
return m_content != NULL;
}
Edit: Your addition to your question follows exactly in this direction.
Ok, so it seems that it is a bug in the Intel C++ compiler and was filed in the bug tracking list.
I have the following code:
#include <iostream>
struct Base {
int i_;
};
class El : protected Base {
public:
int get_i() const { return i_; }
void set_i(int i) { i_ = i; }
};
class It : protected Base {
public:
using pointer = const El*;
using reference = const El&;
reference operator*() const
{
return reinterpret_cast<reference>(*this);
}
pointer operator->() const
{
return reinterpret_cast<pointer>(this);
}
};
int main()
{
It it;
It* itp = ⁢
std::cout << *****(itp)->get_i() << "\n"; //ERROR
}
Both GCC and Clang++ somehow fail to invoke either of operator* or operator->, so I get an error It doesn't have member function 'get_i' in the last line regardless how many indirections I try. Does the standard warrant such unintuitive behavior?
Operator precedence: -> binds more tightly, so is applied to the pointer itp.
When you overload operator->, that doesn't affect the meaning of operator-> applied to a pointer-to-your-class. You want (*itp)->get_i();, I think.