all. I am trying to learn something about template inherit. I want to cast a temp derived object to its base reference. But I come across this problem:
typedef long size64_t;
//////Base class
template <typename _Scalar>
class MatrixBase{
public:
virtual _Scalar operator()(size64_t rowid, size64_t colid) = 0;
};
//////Derived class 1
template <typename _Scalar>
class MatrixHolder : public MatrixBase<_Scalar>{
public:
MatrixHolder(){};
inline _Scalar operator()(size64_t rowid, size64_t colid){return 0;}
};
//////Derived class 2
template <typename _Scalar>
class Matrix : public MatrixBase<_Scalar>{
public:
Matrix(){};
inline _Scalar operator()(size64_t rowid, size64_t colid){return 0;}
};
//////The function with parameters as Base class reference, wanting to get derived object as input.
template <typename _Scalar>
MatrixHolder<_Scalar> apply(MatrixBase<_Scalar>& lhs, MatrixBase<_Scalar>& rhs){
MatrixHolder<_Scalar> result;
return result;
}
and in main, we have:
void main(){
Matrix<double> m1;
Matrix<double> m2;
apply(m1, m2);//Sucess
apply(m1, apply(m1, m2));//Fail
}
the compiler said:
note: candidate function [with _Scalar = double] not viable: no known conversion from
'MatrixHolder<double>' to 'MatrixBase<double> &' for 2nd argument
MatrixHolder<_Scalar> apply(MatrixBase<_Scalar>& lhs, MatrixBase<_Scalar>& rhs){
^
1 error generated.
apply(m1, apply(m1, m2));//Fail
The problem here is that the inner apply returns a temporary, which cannot bind to the non-const reference parameter of the outer apply.
If you can make the parameters MatrixBase<_Scalar> const& it would be a possible match.
Related
I have the following inheritance model:
interface abstract class concrete derived class
_________________________________________________________
IPriorityQueue -> APriorityQueue -> UnsortedPriorityQueue
My member function was declared purely virtual in the interface. In the abstract class, I want to use size() to already implement empty(), since if size = 0, then the priority queue is empty. size() is properly implemented in the derived class.
#include <list>
template <typename K, typename V>
class IPriorityQueue
{
public:
virtual int size(void) const = 0;
virtual bool empty(void) const = 0;
};
template <typename K, typename V>
class APriorityQueue : virtual public IPriorityQueue<K, V>
{
public:
bool empty(void) const { return (!size()); }
};
template <typename K, typename V>
class UnsortedPriorityQueue : virtual public APriorityQueue<K, V>
{
private:
std::list<V> _list;
public:
int size(void) const { return (this->_list.size()); }
};
int main()
{
UnsortedPriorityQueue<int, char> test;
}
However, I get the following error:
../../libft/APriorityQueue.hpp:49:37: error: there are no arguments to 'size' that depend on a template parameter, so a declaration of 'size' must be available [-fpermissive]
bool empty(void) const { return (!size()); }
^~~~
../../libft/APriorityQueue.hpp:49:37: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
I read in some other answers on StackOverflow that one has to specify the namespace, so I modified it the following way:
bool empty(void) const { return (!IPriorityQueue<K, V>::size()); }
But now I get a linker error complaining that IPriorityQueue<K, V>::size() is not implemented:
main.o:main.cpp:(.text$_ZNK14APriorityQueueIiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5emptyEv[_ZNK14APriorityQueueIiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5emptyEv]+0x28): undefined reference to `IPriorityQueue<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::size() const'
collect2.exe: error: ld returned 1 exit status
Is there any way I can figure this out? Is such a design even possible? Thank you in advance
Just replace
bool empty(void) const { return (!size()); }
with
bool empty(void) const { return (!this->size()); }//note i have added this->
and that will solve your problem.
Here's the rule
the compiler does not look in dependent base classes when looking up nondependent names .
Here's a good article for reading more about this.
I can't understand how i can create expr object from double in expr.cpp file.
expr_base:
The base class of all expressions. Note that all expression classes
(including this base) are private to the implementation and should not
be exposed to other code. The rest of the program should use
expressions only via expr.
This subclasses std::enable_shared_from_this to enable getting
shared_ptr to this from a method.
expr:
Wrapper around dynamically allocated instances of expr_base. This type
has value semantics and since all subclasses of expr_base are
immutable, shallow copies are made.
This type has overloaded functions and operators, so that expression
construction is easy and readable.
error:
error: no viable conversion from returned value of type 'typename enable_if<!is_array<number>::value,
shared_ptr<number> >::type' (aka 'std::__1::shared_ptr<exprs::number>') to function return type 'expr'
return std::make_shared<exprs::number>(n);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/..../expr.hpp(...): note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'typename enable_if<!is_array<number>::value, shared_ptr<number> >::type' (aka 'std::__1::shared_ptr<exprs::number>') to 'const expr &' for 1st argument
class expr final {
^
/.../expr.hpp:(...): note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'typename enable_if<!is_array<number>::value, shared_ptr<number> >::type' (aka 'std::__1::shared_ptr<exprs::number>') to 'expr &&' for 1st argument
/.../expr.hpp:(...): note: candidate template ignored: requirement 'std::is_convertible<exprs::number *, const expr_base*>::value' was not satisfied [with T = exprs::number]
expr(std::shared_ptr<T> e): ptr(std::static_pointer_cast<const expr_base>(std::move(e))) {}
expr.hpp
...
class expr;
class expr_base: public std::enable_shared_from_this<expr_base>
{
friend class expr;
protected:
expr_base() = default;
public:
using variable_map_t = std::map<std::string, double>;
virtual ~expr_base() = default;
};
class expr final {
private:
using const_pointer = std::shared_ptr<const expr_base>;
public:
using variable_map_t = expr_base::variable_map_t;
template <typename T, typename = std::enable_if_t<std::is_convertible<T*, const expr_base*>::value>>
expr(std::shared_ptr<T> e): ptr(std::static_pointer_cast<const expr_base>(std::move(e))) {}
expr() = default;
static expr number(double n);
operator const_pointer const &() const {return ptr;}
const expr_base* operator->() const {assert(ptr.get() != nullptr); return ptr.get();}
private:
const_pointer ptr;
};
expr.cpp
...
#include "expr.hpp"
#include "expr_impl.hpp"
expr expr::number(double n) {
return std::make_shared<exprs::number>(n); // It doesn't work
}
expr_impl.hpp
...
#include "expr.hpp"
namespace exprs {
class number:expr_base {
private:
double num_;
public:
number(double num): num_(num) {};
};
}
Suppose I have a templated class:
template<typename T>
class A
{
public:
A(T& val) : m_val{val} {}
T& val() { return m_val; }
const T& val() const { return m_val; }
//etc...
private:
T& m_val;
};
Can I have template specialization which is different for lines (1) and (2):
int a = 5;
A<int> x {a}; //(1)
const A<int> y {a}; //(2)
const int b = 10;
const A<int> z {b}; //error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
Basically, in the const case I want to declare the underlying m_val as const T& m_val; because I've instantiated my wrapper class as const and I want to signify that the internal reference should also be const in this case.
Is this possible? I've tried several solutions and the only one that seem to work is to explicitly add const to the template argument like this: const A<const int> z {b};
Is it possible to avoid this inner const-qualifier?
EDIT: Changed the member variable to be a reference to show how const-ness can cause trouble for the compiler in this situation.
EDIT2: Removed the default constructor to simplify the problem.
The program below generates a compiler error:
MSVC: error C2782: 'double dot(const V &,const V &)': template parameter 'V' is ambiguous
GCC: deduced conflicting types for parameter 'const V' ('Matrix<3, 1>' and 'UnitVector')
I had thought that it would not have this problem because the constructor UnitVector(Vector) is marked explicit, and therefore the arguments (of the call to dot()) can only resolve as Vector with implicit conversions. Can you tell me what I am misunderstanding? Does the compiler consider explicit constructors as implicit conversions when resolving template parameters?
template<int M, int N>
struct Matrix {
};
using Vector = Matrix<3,1>;
struct UnitVector : Vector{
UnitVector(){}
explicit UnitVector(const Vector& v)
{}
operator const Vector&(){
return *static_cast<const Vector*>(this);
}
};
template<typename V>
double dot(const V& a, const V& b){
return 0.0;
}
int main()
{
dot(Vector(),UnitVector());
}
No, that does not work. But actually, you don't need the template
double dot(const Vector &, const Vector &) {...}
works. You don't even need the conversion operator defined in UnitVector. Child to base conversions are done implicitly.
If you want to generally take two types that are implicitly convertible to a common type, the following should work (untested)
template<class U>
double dot_impl(const U&, const U&) {...}
template<class U, class V>
auto dot(const U &u, const V &v) {
return dot_impl<std::common_type_t<U, V>>(u, v);
}
Since the template parameter is explicit, the implicit conversions to thw common type of those two are done in the call, so everything works nice. I moved the original dot to dot_impl, since otherwise we would call dot with one template parameter, which could still be ambiguous.
I have a template class with two template arguments with the following constructor and member:
template <class T, class TCompare>
class MyClass {
...
public:
MyClass(TCompare compare);
void addElement(T newElement);
...
};
And I have a structure which overloads operator () for integer comparison:
struct IntegerLess {
bool operator () {const int& a, const int& b) {
if (a < b)
return true;
return false;
}
};
I create an object of class 'MyClass' and try to use it:
MyClass<int, IntegerLess> myClassObject(IntegerLess());
myClassObject.addElement(10);
However, I got the following compile-time error:
error: request for member ‘addElement’ in ‘myClassObject’, which is of non-class type ‘MyClass<int, IntegerLess>(IntegerLess (*)())’
How can I correct it? Thanks!
This is the most vexing parse. You can fix the problem by throwing in an extra set of parentheses:
MyClass<int, IntegerLess> myClassObject((IntegerLess()));
// ^ ^
Note that if you had passed an lvalue directly, there would have been no scope for this parse:
IntegerLess x;
MyClass<int, IntegerLess> myClassObject(x);
Declare the IntegerLess object separately:
IntegerLess comparator;
MyClass<int, IntegerLess> myClassObject(comparator);
myClassObject.addElement(10);
Alternatively, add parentheses like juanchopanza suggested.