const pointer as a constructor argument - c++

This is an odd one. Note this is cut down example code, and misses out destructors deliberately).
template <class f, class g> class Ptr;
class RealBase
{
};
template <class a, class b, class c = Ptr<a,b> >
class Base : public RealBase
{
public:
Base(){};
};
template <class d, class e>
class Derived : public Base <d,e>
{
public:
Derived(){};
void DerivedMethod(){};
};
typedef Derived<double,double> D_Derived;
template <class f, class g>
class Ptr
{
public:
Ptr(){};
Ptr(Base<f,g,Ptr<f,g> >* a){in = a;};
Base<f,g,Ptr<f,g> >* operator->()
{
return in;
};
Base<f,g,Ptr<f,g> >& operator*()
{
return *in;
};
private:
Base<f,g,Ptr<f,g> >* in;
};
I'm using the Ptr class from this example in a vector, as a pointer to a Derived class.
As we can see, the Ptr takes a Base<>* as it's constructor argument.
Unfortunately I need a constructor that takes a const Base<>*, and I cannot simply do this:
Ptr(const Base<>* a) { in = const_cast<Base<>*>(a)};
Any ideas how I can make this class accept a const Base<>* as it's constructor?
Edit:
Ok, turns out I can fix this by making changes to unrelated code, so it's a bit of a non-problem now =] Took me about a day to fix it though =[

I think you need to define a separate class to wrap pointers to const, since not only the arguments of the constructor, but also the return types of the operators should be changed to const versions. If you make the ConstPtr a friend of Ptr, this should work out quite nicely:
template<...>
class ConstPtr {
const Base<...> *in;
ConstPtr(Base<...>* a) { in = a; }
ConstPtr(const Base<...>* a) { in = a; }
ConstPtr(const Ptr<...> &a) { in = a.in; }
...
};
To construct wrappers from raw pointers you could add an overloaded function, more or less like this:
template<..., class P>
P make_ptr(Base<...> *t);
template<...>
Ptr<...> make_ptr< ..., Ptr<...> >(Base<...> *t) {
return Ptr(t);
}
template<...>
ConstPtr<...> make_ptr< ..., ConstPtr<...> >(const Base<...> *t) {
return ConstPtr(t)
}

Your Ptr class has a non-const pointer member. You will not be able to assign a const Base* without some unsafe casts. Do you want that? Try this instead:
template <class f, class g>
class Ptr
{
public:
Ptr(){};
Ptr(Base<f,g,Ptr<f,g> > const* a) { in = *a; }
Base<f,g,Ptr<f,g> >* operator->()
{
return &in;
};
Base<f,g,Ptr<f,g> >& operator*()
{
return in;
};
private:
Base<f,g,Ptr<f,g> > in;
};

according your example you should do
Ptr( const Base< f,g, Ptr< f, g > >* a )
{
in = const_cast< Base<f,g,Ptr<f,g> >* > ( a );
}
ps: I don't like const_cast and in similar cases I try to avoid this. Maybe need do two implementation of Ptr for const and non const arguments.

Related

Use reference template arguments in inner class

This is my code:
template<class V, class Ref = V&>
class Util {
public:
typedef Ref reference;
};
template<class D, class V, class Ref = V&>
class Base {
public:
class Inner1: public Util<const V, const Ref> {
public:
Inner1(const D &d) :
d(d) {
}
typename Inner1::reference foo() const {
static V v;
return v;
}
private:
const D &d;
};
class Inner2: public Util<V, Ref> {
public:
Inner2(D &d) :
d(d) {
}
typename Inner2::reference foo() const {
static V v;
return v;
}
private:
D &d;
};
};
class Child: public Base<Child, float> {
public:
Inner1 getInner1() const {
return Base<Child, float>::Inner1(*this);
}
Inner2 getInner2() {
return Base<Child, float>::Inner2(*this);
}
};
void print(float & ff) {
}
int main() {
Child c;
Child::Inner1 inner = c.getInner1();
print(inner.foo());
return 0;
}
This code compile without problems but I guess I should receive a compilation error. The method foo of class Inner1 should return a const reference, but for unknown reason Ref is defined without const. Why?
but for unknown reason Ref is defined without const. Why?
Leading const is misleading. In the type Util<const V, const Ref> you const qualify the Ref type. I.e., you supposedly pass V & const as the type, and not V const &. While normally V & const would be ill-formed, when dealing with the type indirectly, such as when it's aliased or a template argument, the extra cv-qualifier is simply ignored.
Personally, I would use the extra template parameter for an entire trait.
template<class V>
class VTrait {
public:
typedef V & reference;
typedef V const & const_reference;
};
template<class D, class V, class Trait = VTrait<V>>
class Base {
public:
class Inner1: public Util<const V, typename Trait::const_reference> {
// ...
};
// ...
};
Client code that wants something different from your framework will need only customize the Trait.
const Ref, given Ref is V&, i.e. float&, note that const is qualified on the reference itself, not the type being referenced. The const qualifier is just omitted, you're still getting V&, but not const V& as you expected. (To be precise there's no const references in C++ but only references to const or to non-const.)
If you change const Ref to const V& (i.e. reference to const), you'll get the error you expected. e.g.
class Inner1: public Util<const V, const V&> {
...

C++ template class operator overloading with the same signatures

A simple C++ OO question regrading templates and operator overloading: In the following class, I have overloaded the index operator twice:
template<class A, class B>
class test
{
A a1;
B a2;
public:
A& operator[](const B&);
B& operator[](const A&);
};
Now, if I instantiate an object of this template class with the same typenames:
test<int, int> obj;
calling the index operator will result in an error, because the two overloaded functions will have the same signatures.
Is there any way to resolve this issue?
Sorry, if this is a basic question. I am still learning!
You can add a partial specialization:
template<class A>
class test<A, A>
{
A a1, a2;
public:
A& operator[](const A&);
};
You can avoid this issue and make the code more robust and expressive by converting the index to some other type that clarifies what the user wants. Usage would be like this:
bidirectional_map<int, int> myTest;
int& valueFor1 = myTest[Key{1}];
int& key1 = myTest[Value{valueFor1}];
Implemented like this:
template<class TKey>
struct Key { const TKey& key; };
template<class TValue>
struct Value { const TValue& value; };
// Deduction guides (C++17), or use helper functions.
template<class TValue>
Value(const TValue&) -> Value<TValue>;
template<class TKey>
Key(const TKey&) -> Key<TKey>;
template<class TKey, class TValue>
class bidirectional_map
{
TKey a1; // Probably arrays
TValue a2; // or so?
public:
TValue & operator[](Key<TKey> keyTag) { const TKey & key = keyTag.key; /* ... */ }
TKey & operator[](Value<TValue> valueTag) { const TValue& value = valueTag.value; /* ... */ }
};
Now, Key and Value are popular names so having them "taken up" by these auxiliary functions is not the best. Also, this is all just a pretty theoretical exercise, because member functions are of course a much better fit for this task:
template<class TKey, class TValue>
class bidirectional_map
{
TKey a1; // Probably arrays
TValue a2; // or so?
public:
TValue& getValueForKey(const TKey& key) { /* ... */ }
TKey& getKeyForValue(const TValue& value) { /* ... */ }
};
In C++2a, you might use requires to "discard" the function in some case:
template<class A, class B>
class test
{
A a1;
B a2;
public:
A& operator[](const B&);
B& operator[](const A&) requires (!std::is_same<A, B>::value);
};
Demo
Here is an example solution using if constexpr that requires C++17:
#include <type_traits>
#include <cassert>
#include <string>
template <class A, class B>
class test
{
A a1_;
B b1_;
public:
template<typename T>
T& operator[](const T& t)
{
constexpr bool AequalsB = std::is_same<A,B>();
constexpr bool TequalsA = std::is_same<T,A>();
if constexpr (AequalsB)
{
if constexpr (TequalsA)
return a1_; // Can also be b1_, same types;
static_assert(TequalsA, "If A=B, then T=A=B, otherwise type T is not available.");
}
if constexpr (! AequalsB)
{
constexpr bool TequalsB = std::is_same<T,B>();
if constexpr (TequalsA)
return a1_;
if constexpr (TequalsB)
return b1_;
static_assert((TequalsA || TequalsB), "If A!=B, then T=A || T=B, otherwise type T is not available.");
}
}
};
using namespace std;
int main()
{
int x = 0;
double y = 3.14;
string s = "whatever";
test<int, int> o;
o[x];
//o[y]; // Fails, as expected.
//o[s]; // Fails, as expected
test<double, int> t;
t[x];
t[y];
//t[s]; // Fails, as expected.
return 0;
};

Is there a "dynamic decltype"?

This question is related to decltype and multiple inheritance.
Assume I have the following:
an abstract class A with a few virtual methods,
a few derived classes that implement methods using the previous virtual ones (each of these classes is a sort of use-case),
a final concrete class that inherits from a subset of the previous use-cases and implements the pure virtual methods.
For example:
#include <iostream>
/**
* "Iterable container"
*/
template <class T>
struct A
{
virtual T* data() =0;
virtual const T* data() const =0;
virtual unsigned size() const =0;
T* begin() { return data(); }
T* end() { return data()+size(); }
const T* begin() const { return data(); }
const T* end() const { return data()+size(); }
};
// ------------------------------------------------------------------------
/**
* Iterative assignment
*/
template <class T>
struct B: public A<T>
{
auto operator =( const T& val ) -> decltype(*this)
{
for ( auto& v: *this ) v = val;
return *this;
}
};
/**
* Iterative display
*/
template <class T>
struct C: public A<T>
{
void show() const
{
for ( auto& v: *this )
std::cout<< v << " ";
std::cout<< std::endl;
}
};
// ------------------------------------------------------------------------
/**
* Concrete implementation
*/
template <class T, unsigned N>
struct D:
public B<T>,
public C<T>
{
using B<T>::operator=;
T dat[N];
T* data() { return dat; }
const T* data() const { return dat; }
unsigned size() const { return N; }
};
// ------------------------------------------------------------------------
int main()
{
D<double,5> d;
(d = 42).show(); // compile-time error, "no member named 'show' in 'B<double>'"
}
The problem is this (no pun intended); if one of the "use-case" method should return a reference to *this, I would like this to be a reference to the final concrete class, so that I could chain the call with other methods from other use-cases.
With the previous implementation however, I'm getting a compile-time error. Is there another way to achieve what I explained?
The solution is to use CRTP; you tell B to return an lvalue reference to D<T, N> by passing the most derived type as an additional template parameter.
template <class T, class Derived>
struct B: public A<T>
{
auto operator =( const T& val ) -> Derived&
// ...
template <class T, unsigned N>
struct D:
public B<T, D<T, N>>,
// ...
You can give D an overriding operator= that returns a D &:
auto operator =( const T& val ) -> decltype(*this) override
{
B<T>::operator=(val);
return *this;
}
This works because D & is covariant with B &, and overriding functions must have a covariant return type. This currently shadows B's operator=, too, because that one is not virtual.

Copy constructor with smart pointer

I have a class with one std::unique_ptr as class member. I was wondering, how to correctly define the copy constructor, since I'm getting the following compiler error message: error C2248: std::unique_ptr<_Ty>::unique_ptr : cannot access private member declared in class 'std::unique_ptr<_Ty>. My class design looks something like:
template <typename T>
class Foo{
public:
Foo(){};
Foo( Bar<T> *, int );
Foo( const Foo<T> & );
~Foo(){};
void swap( Foo<T> & );
Foo<T> operator = ( Foo<T> );
private:
std::unique_ptr<Bar> m_ptrBar;
int m_Param1;
};
template < typename T >
Foo<T>::Foo( const Foo<T> & refFoo )
:m_ptrBar(refFoo.m_ptrBar),
m_Param1(refFoo.m_Param1)
{
// error here!
}
template < typename T >
void Foo<T>::swap( Foo<T> & refFoo ){
using std::swap;
swap(m_ptrBar, refFoo.m_ptrBar);
swap(m_Param1, refFoo.m_Param1);
}
template < typename T >
Foo<T> Foo<T>::operator = ( Foo<T> Elem ){
Elem.swap(*this);
return (*this);
}
Assuming the goal is to copy-construct the uniquely-owned Bar,
template < typename T >
Foo<T>::Foo( const Foo<T> & refFoo )
: m_ptrBar(refFoo.m_ptrBar ? new Bar(*refFoo.m_ptrBar) : nullptr),
m_Param1(refFoo.m_Param1)
{
}
Unique_ptr documentation:
Stores a pointer to an owned object. The object is owned by no other unique_ptr.
The object is destroyed when the unique_ptr is destroyed.
You cant copy it because two objects can't own it.
Try switching to a std::shared_ptr.
EDIT I should point out that this would make both objects have a pointer to that same object. If you want to copy the uniquely owned object Cubbi's solution is the correct one.
A possibility is to create a new clone_ptr type for this.
Below is a rudimentary example of a clone_ptr that invokes the correct copy constructor (and destructor) of a derived object. This is done here by creating a "type erasure" helper when the clone_ptr is created.
Other implementations may be found on the Internet.
#include <memory>
namespace clone_ptr_detail
{
template <class T>
class clone_ptr_helper_base
{
public:
virtual ~clone_ptr_helper_base() {}
virtual T* clone(const T* source) const = 0;
virtual void destroy(const T* p) const = 0;
};
template <class T, class U>
class clone_ptr_helper: public clone_ptr_helper_base<T>
{
public:
virtual T* clone(const T* source) const
{
return new U(static_cast<const U&>(*source));
}
virtual void destroy(const T* p) const
{
delete static_cast<const U*>(p);
}
};
}
template <class T>
class clone_ptr
{
T* ptr;
std::shared_ptr<clone_ptr_detail::clone_ptr_helper_base<T>> ptr_helper;
public:
template <class U>
explicit clone_ptr(U* p): ptr(p), ptr_helper(new clone_ptr_detail::clone_ptr_helper<T, U>()) {}
clone_ptr(const clone_ptr& other): ptr(other.ptr_helper->clone(other.ptr)), ptr_helper(other.ptr_helper) {}
clone_ptr& operator=(clone_ptr rhv)
{
swap(rhv);
return *this;
}
~clone_ptr()
{
ptr_helper->destroy(ptr);
}
T* get() const { /*error checking here*/ return ptr; }
T& operator* () const { return *get(); }
T* operator-> () const { return get(); }
void swap(clone_ptr& other)
{
std::swap(ptr, other.ptr);
ptr_helper.swap(other.ptr_helper);
}
};
See usage example: http://ideone.com/LnWa3
(But perhaps you don't really need to copy your objects, and might rather explore the possibilities of move semantics. For example, you can have a vector<unique_ptr<T>>, as long as you don't use functions that copy the contents.)

Using STL algorithms (specifically std::sort) from within a templated class

I've declared a template class MyContainer as bellow, then created an instance of it of type DataType1. The DataType1 class provides a friend function "DataSpecificComparison" which is used by std::sort to compare DataType1 objects. The program compiled and sorted correctly.
I then defined a class called DataType2, gave it a friend implementation of "DataSpecificComparison" and used it to create another instance of MyContainer.
I am now unable to compile the program as a "C2914: 'std::sort' : cannot deduce template argument as function argument is ambiguous" compile time error is reported.
How can a developer specify that the DataSpecificComparison binary predicate is to take arguments of template type T*? Or is there another way around this issue?
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
....
public:
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison)
}
}
class DataType1
{
....
friend bool DataSpecificComparison(const DataType1 * lhs, const DataType1 * rhs)
}
class DataType2
{
....
friend bool DataSpecificComparison(const DataType2* lhs, const DataType2* rhs)
}
You can use a temporary local function pointer variable of the required type to select the correct overload of DataSpecificComparison:
void SortMyContainerObjects()
{
typedef bool (*comparer_t)(const T*, const T*);
comparer_t cmp = &DataSpecificComparison;
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), cmp);
}
Here the compiler can deduce that you want to use the DataSpecificComparison overload that matches the comparer_t type, which resolves the ambiguity.
sth already gave a correct answer, but there's also a direct alternative based on the same principle:
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(),
static_cast<bool (*comparer_t)(const T*, const T*)>(&DataSpecificComparison));
}
This uses essentially the same mechanism. The cast forces overload resolution to happen before the Template Argument Deduction for std::sort.
template<typename T>
struct DataSpecificComp : public binary_function<T, T, bool>
{
public:
bool operator()(const T* lhs, const T* rhs)
{
return *lhs < *rhs;
}
};
call the sort function as shown below:
sort(vi.begin(), vi.end(), DataSpecificComp<int>());
I'd prefer something along the following lines: by default it compares objects with less_than (so you wouldn't have to remember to provide a function with a funny name), and there's an overload that allows giving your own comparison functor (again, value-based):
#include <vector>
#include <algorithm>
#include <functional>
template <class T, class Func>
struct indirect_binary_call_type: public std::binary_function<const T*, const T*, bool>
{
Func f;
indirect_binary_call_type(Func f): f(f) {}
bool operator()(const T* a, const T* b) const
{
return f(*a, *b);
}
};
template <class T, class Func>
indirect_binary_call_type<T, Func> indirect_binary_call(Func f)
{
return indirect_binary_call_type<T, Func>(f);
}
template <class T>
class MyContainer
{
private:
std::vector<T*> m_vMyContainerObjects;
public:
void Sort()
{
Sort(std::less<T>());
}
template <class Func>
void Sort(Func f )
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), indirect_binary_call<T>(f));
}
};
int main()
{
MyContainer<int> m;
m.Sort();
m.Sort(std::greater<int>());
}
Did you try defining DataSpecificComparison as template with bunch of specializations and giving it the type?
template<T>
bool DataSpecificComparison(const T* t1, const T* t2)
{
// something non compilable here
}
template<> bool DataSpecificComparison<Data1>(const Data1* t1, const Data1* t2)
{
// return *t1 < *t2;
}
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison<T>)
}
....
Templating DataSpecificComparison should work. You can also specifically call the proper std::sort template, but it's a bit cumbersome:
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
typedef bool (*compsT)(T, T);
public:
....
void SortMyContainerObjects()
{
std::sort<std::vector<T*>::iterator, compsT>(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison);
}
}