I've got this code:
template<typename A, typename B = A>
class MyClass;
template<typename A>
class MyClass<A, void>
{
protected:
A a;
MyClass<A, void>(const A& a):
a(a)
{}
public:
const A& getA() const
{
return a;
}
};
template<typename A, typename B>
class MyClass : public MyClass<A, void>
{
private:
B b;
public:
MyClass<A, B>(const A& a, const B& b):
MyClass<A, void>(a), b(b)
{}
const B& getB() const
{
return b;
}
const auto getAplusB() const
{
return a+b;
}
};
getAplusB method fails to compile with message a is not declared. However, inheritance seems to work, so I can use this->getA() + b. I've also tried to do dynamic_cast<const MyClass<A, void>*>(this)->a + b, but got another compilation error a is protected. What am I missing here?
You will need to simply use this->a or a qualified name MyClass<A, void>::a. This is because a is member of a base class-template. There is such a thing known as name lookup - When the compiler sees a name, it does the said name lookup.
Simply trying to make unqualified accesses a will not work because it's a dependent name (by meaning of it depending on the instantiation of some template somewhere). Hence you have to qualify the accesses to a
Related
I have a class A and a class B, both generic with a type parameter T. An object of A<T> can be casted to B<T>. I have a generic operator overload on B that I want to be able to call on an A object and a B object, where the A object gets implicitly converted.
When I try this it does not compile:
template <typename T>
class A {};
template <typename T>
class B {
public:
B() {}
B(const A<T> &a) {}
};
template <typename T>
B<T> operator*(const B<T> &obj1, const B<T> &obj2) {
return B<T>(); // doesn't matter
}
int main() {
A<int> objA;
B<int> objB;
B<int> combined1 = objA * objB; // error: operator* isn't defined on these types
B<int> combined2 = static_cast<B<int>>(objA) * objB; // fine
return 0;
}
However when A and B aren't generic, it works fine:
class A {};
class B {
public:
B() {}
B(const A &a) {}
};
B operator*(const B &obj1, const B &obj2) {
return B(); // doesn't matter
}
int main() {
A objA;
B objB;
B combined1 = objA * objB; // fine
B combined2 = static_cast<B>(objA) * objB; // also fine
return 0;
}
Why is this? Is there something about making the operator overload generic that means the type can't be inferred?
In general, implicit conversions are not allowed while doing argument deduction, I can think of a derived to base as one that is allowed. The expression
B<int> combined1 = objA * objB;
expect to find viable overloads for objA * objB, including those found by ADL, one possible is:
template <typename T>
B<T> operator*(const A<T> &obj1, const B<T> &obj2) {...}
but none is found, the overload you provide is not a candidate, hence the call fail, but if you provide the explicit template argument to the operator, then there will be nothing to deduce and the implicit conversion through the converting constructor will allow the call:
B<int> combined1 = operator*<int>(objA, objB);
But I would not do that, stick with the cast it better explain the intent.
You can define friend function in class A which call your template function
template <class T>
class B;
template <typename T>
class A {
friend B<T> operator*(const B<T> &obj1, const B<T> &obj2) {} # here call template function
};
template <typename T>
class B {
public:
B() {}
B(const A<T> &a) {}
};
template <typename T>
B<T> operator*(const B<T> &obj1, const B<T> &obj2) {
return B<T>(); // doesn't matter
}
int main() {
A<int> objA;
B<int> objB;
B<int> combined1 = objA * objB; // fine
B<int> combined2 = static_cast<B<int>>(objA) * objB; // fine
return 0;
}
During argument deduction, conversion/promotion doesn't occurs, so for
objA * objB
When checking validity of candidates overload, T cannot be deduced for:
template <typename T> B<T> operator*(const B<T> &, const B<T> &);
So that overload is rejected.
One way to fix that is to create a non template function. Asit should apply to classe template, one way to do it is with friend functions:
template <typename T>
class B {
public:
B() {}
B(const A<T>&) {}
friend B operator*(const B&, const B&) { return /*...*/; }
};
Now, objA * objB considers overload B<int> operator*(const B<int>&, const B<int>&) and conversion can occurs to see if function is viable (and it is).
Demo
In this minimal example I have a class A with an operator + defined outsise of it:
template<class T> class A {};
template<class T1, class T2> void operator+(A<T1> a, A<T2> b) {}
template<class T> class B : public A<T> {};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
I've tried to create an implicit conversion from B to A but it requires the operator+ to be a friend of A and be defined inside A which will cause problems when more than one instance of A<...> gets instantiated.
So, is there any other way to do this without having to define the operator+ again?
Thank you in advance for any help.
template<class T> class A {
template<class T2>
friend void operator+(A const& lhs, A<T2> const& rhs) {}
};
template<class T> class B : public A<T> {};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
this works. The assymetry in + (one template, one not) ensure that multiple As don't conflict with their +.
In some situations you really need lhs to be an instance of B:
template<class T> struct A {
template<class D, class T2, std::enable_if_t<std::is_base_of<A, D>{}, bool> =true >
friend void operator+(D const& lhs, A<T2> const& rhs) {
std::cout << D::name() << "\n";
}
static std::string name() { return "A"; }
};
template<class T> struct B : public A<T> {
static std::string name() { return "B"; }
};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
which uses A's operator+, but the LHS is of type B. Doing this for B<T2> on the right hand side isn't very viable, it gets ridiculous.
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();
}
I have a template class:
template<class T>
class A{
T a, b;
public:
A(A<T> const & o) : a(o.a), b(o.b){}
A(T const & _a, T const & _b) : a(_a), b(_b){}
};
A<double> d(1.2, 4.5);
A<float> f = d; //error: conversion from A<double> to non-scalar type A<float> requested
How do i define a conversion function for my class?
My compiler is g++ 4.7.0
You could make a template constructor:
template<class T>
class A{
T a, b;
public:
template<class U>
A(A<U> const & rhs) : a(rhs.a), b(rhs.b) {}
A(T const & _a, T const & _b) : a(_a), b(_b){}
};
Then you should be able to convert any class A<U> to any class A<T> as long as U is convertible to T.
What you're trying to do is not a good idea.
However, to get over the compiler error, you can specialize the class -
template <>
class A<float>
{
public:
A(A<double> const & o) {}
};
I'm trying to understand whay i get an error on this code:
(the error is under g++ unix compiler. VS is compiling OK)
template<class T> class A {
public:
T t;
public:
A(const T& t1) : t(t1) {}
virtual void Print() const { cout<<*this<<endl;}
friend ostream& operator<<(ostream& out, const A<T>& a) {
out<<"I'm "<<typeid(a).name()<<endl;
out<<"I hold "<<typeid(a.t).name()<<endl;
out<<"The inner value is: "<<a.t<<endl;
return out;
}
};
template<class T> class B : public A<T> {
public:
B(const T& t1) : A<T>(t1) {}
const T& get() const { return t; }
};
int main() {
A<int> a(9);
a.Print();
B<A<int> > b(a);
b.Print();
(b.get()).Print();
return 0;
}
This code is giving the following error:
main.cpp: In member function 'const T& B::get() const':
main.cpp:23: error: 't' was not declared in this scope
It did compiled when i changed the code of B to this:
template<class T> class B : public A<T> {
public:
B(const T& t1) : A<T>(t1) {}
const T& get() const { return A<T>::t; }
};
I just cant understand what is the problem with the first code...
It doesn't make sense that i really need to write "A::" every time...
You can also use this->t to access the base class template member.
In B::get(), the name t is not dependent on the template parameter T, so it is not a dependent name. Base class A<T> is obviously dependent on the template parameter T and is thus a dependent base class. Nondependent names are not looked up in dependent base classes. A detailed description of why this is the case can be found in the C++ FAQ Lite.