Use reference template arguments in inner class - c++

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&> {
...

Related

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.

How to keep track of Eigen objects through a solve()?

This question is related to cast from Eigen::CwiseBinaryOp to MatrixXd causes segfault .
It will probably have as simple a solution as the former.
In this minimal example, I define Holder, which holds and Eigen matrix, and returns it via its get() member function. Similarly, Decomp is an expression template for the LDLT decomposition of this matrix, and Solve solves for AX=B, yielding X.
#include <Eigen/Dense>
#include <Eigen/Cholesky>
template <class EigenType> class Holder {
public:
typedef EigenType result_type;
private:
result_type in_;
public:
Holder(const EigenType& in) : in_(in) {}
const result_type& get() const { return in_; }
};
template <class Hold> class Decomp {
public:
typedef typename Eigen::LDLT
<typename Eigen::MatrixBase<typename Hold::result_type>::PlainObject>
result_type;
private:
Hold mat_;
public:
Decomp(const Hold& mat) : mat_(mat) {}
result_type get() const { return mat_.get().ldlt(); }
};
template <class Derived, class OtherDerived> class Solve {
public:
typedef typename Eigen::internal::solve_retval
<typename Derived::result_type, typename OtherDerived::result_type>
result_type;
private:
Derived decomp_;
// typename Derived::result_type decomp_;
OtherDerived mat_;
public:
Solve(const Derived& decomp, const OtherDerived& mat)
: decomp_(decomp), mat_(mat) {}
//: decomp_(decomp.get()), mat_(mat) {}
result_type get() const { return decomp_.get().solve(mat_.get()); }
// result_type get() const { return decomp_.solve(mat_.get()); }
};
typedef Holder<Eigen::MatrixXd> MatrixHolder;
typedef Decomp<MatrixHolder> MatrixDecomp;
typedef Solve<MatrixDecomp, MatrixHolder> SimpleSolve;
The following test fails on X.get()
#include "Simple.h"
#include <Eigen/Dense>
#include <iostream>
int main(int, char * []) {
MatrixHolder A(Eigen::MatrixXd::Identity(3, 3));
MatrixHolder B(Eigen::MatrixXd::Random(3, 2));
MatrixDecomp ldlt(A);
SimpleSolve X(ldlt, B);
std::cout << X.get() << std::endl;
return 0;
}
but if you use the commented out lines in the header file, everything works fine. Unfortunately, this moves the evaluation of the decomposition to the construction of the solver, which is not suited to my use. Typically, I want to build a complicated expression expr involving this Solve, and call expr.get() later on.
How can I solve this problem? Is there a general rule to follow, to avoid further related questions?
To avoid useless and expensive copies, the internal solve_retval structure stores the decomposition and right-hand-side by const references. However, the LDLT object created in the Decomp::get function is deleted at the same time this function returns, and thus the solve_retval object references dead objects.
One possible workaround, is to add a Decomp::result_type object in Solve, and initialize it in Solve::get. Moreover, to avoid multiple deep copies, I suggest to use const references for a few attributes as follow:
#include <Eigen/Dense>
#include <Eigen/Cholesky>
template <class EigenType> class Holder {
public:
typedef EigenType result_type;
private:
result_type in_;
public:
Holder(const EigenType& in) : in_(in) {}
const result_type& get() const { return in_; }
};
template <class Hold> class Decomp {
public:
typedef typename Eigen::LDLT
<typename Eigen::MatrixBase<typename Hold::result_type>::PlainObject>
result_type;
private:
const Hold& mat_;
mutable result_type result_;
mutable bool init_;
public:
Decomp(const Hold& mat) : mat_(mat), init_(false) {}
const result_type& get() const {
if(!init_) {
init_ = true;
result_.compute(mat_.get());
return result_;
}
}
};
template <class Derived, class OtherDerived> class Solve {
public:
typedef typename Eigen::internal::solve_retval
<typename Derived::result_type, typename OtherDerived::result_type>
result_type;
private:
const Derived& decomp_;
const OtherDerived& mat_;
public:
Solve(const Derived& decomp, const OtherDerived& mat)
: decomp_(decomp), mat_(mat) {}
result_type get() const {
return decomp_.get().solve(mat_.get());
}
};
The general rule is to store heavy objects by const reference (to avoid deep copies) and lightweight expressions by value (to reduce temporary life issues).

Is it okay to remove const qualifier when the call is from the same non-const version overloaded member function?

For example:
struct B{};
struct A {
const B& findB() const { /* some non trivial code */ }
// B& findB() { /* the same non trivial code */ }
B& findB() {
const A& a = *this;
const B& b = a.findB();
return const_cast<B&>(b);
}
};
The thing is I want to avoid repeating the same logic inside the constant findB and non-constant findB member function.
Yes, you can cast the object to const, call the const version, then cast the result to non-const:
return const_cast<B&>(static_cast<const A*>(this)->findB());
Casting away const is safe only when the object in question was not originally declared const. Since you are in a non-const member function, you can know this to be the case, but it depends on the implementation. Consider:
class A {
public:
A(int value) : value(value) {}
// Safe: const int -> const int&
const int& get() const {
return value;
}
// Clearly unsafe: const int -> int&
int& get() {
return const_cast<int&>(static_cast<const A*>(this)->get());
}
private:
const int value;
};
Generally speaking, my member functions are short, so the repetition is tolerable. You can sometimes factor the implementation into a private template member function and call that from both versions.
I think, that using cast here is ok, but if you definitely want to avoid it, you can use some template magic:
struct B
{
B(const B&)
{
std::cout << "oops I copied";
}
B(){}
};
struct A {
public:
A(){}
A(const A&){ std::cout << "a is copied:(\n";}
const B& findB() const { return getter(*this); }
B& findB() { return getter(*this); }
private:
template <typename T, typename V>
struct same_const
{
typedef V& type;
};
template <typename T, typename V>
struct same_const<const T, V>
{
typedef const V& type;
};
template <typename T>
static typename same_const<T,B>::type getter(T& t) { return t.b;}
B b;
};
int main()
{
A a;
const A a_const;
const B& b1 = a.findB();
B& b2 = a.findB();
const B& b3 = a_const.findB();
//B& b4 = a_const.findB();
}

const pointer as a constructor argument

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.