I know you can overload templates based on their template parameters:
template <class T> void test() {
std::cout << "template<T>" << std::endl;
}
void test() {
std::cout << "not a template" << std::endl;
}
then inside some function:
test<int>();
test();
will correctly resolve which of the 2 different versions of test() you want. However, if I now do this inside classes with inheritance:
class A {
public:
void test() {
std::cout << "A::Test: not a template" << std::endl;
}
};
class B : public A {
public:
template <class T>
void test() {
std::cout << "B::Test: template<T>" << std::endl;
}
};
then inside a function:
B b;
b.test<int>();
b.test();
b.test<int>(); works but b.test(); does not:
error: no matching function for call to ‘B::test()’
note: candidate is:
note: template<class T> void B::test()
Why is this/ is there any way to make it correctly resolve the 2 versions based on the template arguments?
As always, a name defined in a derived class hides uses of the same name in a base class. To hoist the name in the base class into the derived class, add
using A::test;
to the derived class.
What you are observing is called name hiding. The name test in the derived class hides test in the base class. Without a using declaration that name will never be found when called through the exact type of that object (casting to base or explicitly qualifying the call also helps).
Related
Is there some way that I can make sure that the base classes function is called from the overridden function in the child class.
Example:
#include <iostream>
class Base
{
public:
virtual void func()
{
std::cout << "Really important code was ran" << std::endl;
}
};
class ChildExplicit : public Base
{
void func() override
{
Base::func();
std::cout << "child class explicitly calling Base::func" << std::endl;
}
};
class ChildImplicit : public Base
{
void func() override
{
std::cout << "child not explicitly calling Base::func" << std::endl;
}
};
int main()
{
Base* explicitChild = new ChildExplicit();
Base* implicitChild = new ChildImplicit();
explicitChild->func();
std::cout << std::endl;
implicitChild->func();
}
This should either output this:
Really important code was ran
child class explicitly calling Base::func
Really important code was ran
child not explicitly calling Base::func
or yield some kind of error that Base::func was not called in ChildImplicit::func.
One solution that would be possible is to make func non virtual and creating a second protected function that will be called in Base::func, the child classes would then override the protected function. But as you can imagine if apply this to a Base class of the Base class of the Base class scenario and each of there implementations must be called this gets quite messy. Would there be an other way to achieve the same goal?
I understand the basic concept of virtual function and vtable,
but in the following example, I don't understand why c.A(); prints out
parent A
child
but without the virtual keyword for Parent::func(), it prints out
parent A
parent
Would you let me know the reason in detail? It would be great to explain with v table, memory (heap, stack), etc..
Thanks.
#include <iostream>
template <class TYPE> class Parent
{
public:
Parent() {};
~Parent() {};
virtual void func() { std::cout << "parent" << std::endl; };
void A() {
std::cout << "parent A" << std::endl;
func();
}
};
template <class TYPE> class Child : public Parent <TYPE>
{
public:
Child() {};
~Child() {};
void func() { std::cout << "child" << std::endl; };
};
void main()
{
Child<int> c;
c.A();
}
The virtual key word specifies that the function can be redefined in a derived class, while preserving its calling properties though references. This is basically the trigger for polymorphic behavior. If the function is declared virtual and it is redefined in a derived class then the vtable is utilized to select the appropriate version of the function unless a specific namespace is specified. For example Parent::func(). Despite having the same name, without the key word virtual the two functions you named func() are completely different. There is no reference available to the base class that can access the derived class's version of the function. It uses the only version func() it knows about, which is the one defined in the base class.
#Pemdas gave a nice explanation. Here is my try.
c.A() tells compiler "I am gonna call the non virtual function A defined in my parent class". This translates to Parent::A(&c)
The A method in class Parent translates to "get the vtable of object &c, grab the function pointer in first row, and call it". Since c reimplements the function func, the function pointer would be c's implementation of function func. That would be what you see.
I am confused how the class inherits from the class RecursiveASTVisitor by passing itself as a template argument. Also, does writing Rewrite(R) in the line
MyRecursiveASTVisitor(Rewriter &R) : Rewrite(R) { }
assign the value R to the variable Rewrite? There is no class Rewrite defined anywhere in the code. Is the ":" operator used for things other than inheriting from a class?
class MyRecursiveASTVisitor
: public RecursiveASTVisitor<MyRecursiveASTVisitor>
{
public:
MyRecursiveASTVisitor(Rewriter &R) : Rewrite(R) { }
void InstrumentStmt(Stmt *s);
bool VisitStmt(Stmt *s);
bool VisitUnaryOperator(UnaryOperator *e);
Rewriter &Rewrite;
};
Its called curiously recurring template pattern. When compiler creates RecursiveASTVisitor<MyRecursiveASTVisitor> it knows layout of MyRecursiveASTVisitor so its all OK.
You can read more on wikipedia
As the comments mentioned, this is known as the Curiously Recurring Template Pattern. This pattern is often implemented to provide a mechanism similar to virtual functions, but at compile time (static polymorphism). For example, RecursiveASTVistor<T> might contain a method that does the following:
...
//using T = MyRecursiveASTVisitor; for your specific case
T *concrete_visitor = static_cast<T*>(this);
concrete_visitor->VisitStmt(something);
If VisitStmt is defined in your MyRecursiveASTVisitor class, then that method is called, otherwise it calls the base definition provided by RecursiveASTVistor. Callers outisde of your class hierarchy also get to take advantage of this static polymorphism.
Here is a short example to help you gain a better intuition of what's happening:
#include <iostream>
template <class T>
struct Base {
void foo() {
T *concrete = static_cast<T*>(this);
concrete->foo();
};
void bar() {std::cout << "Base" << std::endl; }
};
struct Derived : public Base<Derived> {
void foo() {std::cout << "Derived" << std::endl;}
};
int main() {
Base<Derived> b;
b.foo();
b.bar();
}
Output
Derived
Base
Edit: To answer your additional question:
Also, does writing Rewrite(R) in the line
MyRecursiveASTVisitor(Rewriter &R) : Rewrite(R) { } assign the value
R to the variable Rewrite? There is no class Rewrite defined anywhere
in the code. Is the ":" operator used for things other than inheriting
from a class?
Rewrite is a member variable of your MyRecursiveASTVisitor class and is a reference to an object of type Rewriter. The : operator is used in the definition of a constructor to signify a member initializer list. In this case, we simply initialize the Rewrite variable with the passed in argument R. Just to be clear, MyRecursiveASTVisitor(Rewriter &R) : Rewrite(R) { } is a constructor definition for your class MyRecursiveASTVisitor, it is not the class definition.
Below is the code to recreate the problem I am having. Base class is a template class with the virtual function foo. foo has a default implementation that adds the passed in arguments.
SimpleDerived derives from Base, specializing it with std::string. SimpleDerived overloads the virtual Base<T>::foo() function. This class compiles fine and its foo outputs as expected when called in main.
#include <iostream>
template<class T>
struct Base
{
virtual void foo(T val)
{
T local = val + val; // THE OFFENDING LINE OF CODE
std::cout << "Base" << std::endl;
}
};
struct SimpleDerived : public Base<std::string>
{
virtual void foo(std::string val)
{
std::cout << "SimpleDerived" << std::endl;
}
};
struct SimpleObject
{
int value;
};
struct ComplexDerived : public Base<SimpleObject>
{
virtual void foo(SimpleObject val)
{
std::cout << "ComplexDerived" << std::endl;
}
};
int main(void)
{
Base<int> base;
base.foo(2);
SimpleDerived simpleDerived;
simpleDerived.foo("hello world");
SimpleObject object;
ComplexDerived complexDerived;
complexDerived.foo(object);
return 0;
}
ComplexDerived derives from Base, specializing it with a custom struct SimpleObject. ComplexDerived overloads foo as well. However, this is the root of the problem. If I try to compile this I get:
quicktest.cpp: In member function ‘void Base<T>::foo(T) [with T = SimpleObject]’:
quicktest.cpp:47:1: instantiated from here
quicktest.cpp:8:19: error: no match for ‘operator+’ in ‘val + val’
Obviously, there is no operator "+" for SimpleObject. But here is my confusion.. the compiler is being asked to implement Base<SimpleObject>::foo because this is what ComplexDerived inherits from. However, I never use or call Base<SimpleObject>::foo. So should the compiler be trying to generate this base class function?
Paragraph 14.7.1/10 of the C++11 Standard specifies:
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual
member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates
a virtual member function of a class template if the virtual member function would not otherwise be instantiated. [...]
In other words, the behavior in this case is implementation-specific.
While in theory the compiler could figure out that the call to the base class's implementation of foo() won't ever be invoked (since the function call does not occur through a reference or pointer) and avoid instantiating it, this behavior is not mandated by the Standard.
I would like to know if the following code are valid.
The original intension is that, I like a base class that dispatch calls to a certain member to either derived class members if it is there or fall back to default behaviors if derived class does not have this member. Another use is that this base class can be used by itself and the Derived template parameter becomes a implementation policy. Anyway, the following MWE compiles and runs correctly with clang++, Intel, icpc and MSVS. However it fails with g++ (from 4.4 to 4.6, any version I had a hand on) with the error message at the end of the question.
If I change the call at point (1), (2), (3) to call_dispatch (which was the sort of thing I did originally), g++ does not complain anymore. I don't think it is a good practice to have the dispatch function and the caller having the same name. I was just curious if it will work, and curiously enough to try it out (I have no idea how does this idea come to me). My rationale behind this is that, at pint (1), call is invoked with one parameter, so the overload resolution will not match its caller, the zero parameter one. It will not match the SFINAE one at point (2) either, since D2 does not have the member, and then it shall match the one at point (3). Just as in the situation when (1)-(3) are named call_dispatch.
But g++ does not agree with me and other compilers. So, is it an incorrect implementation of g++ or the code itself is invalid? Besides the error message is really confusing. Where does the void (B<D2>::*)() and &B<D2>::call come from? Int he called the member pointer was defined as D2's member.
#include <iostream>
#include <functional>
template <typename Derived>
class B
{
public :
void call ()
{
call<Derived>(0); //----------------------------------------- (1)
}
private :
template <typename D, void (D::*)()> class SFINAE {};
template <typename D>
void call (SFINAE<D, &D::call> *) //---------------------------- (2)
{
static_cast<Derived *>(this)->call();
}
template <typename D>
void call (...) //--------------------------------------------- (3)
{
std::cout << "Call B" << std::endl;
}
};
class D1 : public B<D1>
{
public :
void call ()
{
std::cout << "Call D1" << std::endl;
}
};
class D2 : public B<D2> {};
int main ()
{
D1 d1;
D2 d2;
d1.call();
d2.call();
return 0;
}
Error:
foo.cpp: In member function ‘void B<Derived>::call() [with Derived = D2]’:
foo.cpp:48:13: instantiated from here
foo.cpp:11:9: error: ‘&B<D2>::call’ is not a valid template argument for type ‘void (D2::*)()’ because it is of type ‘void (B<D2>::*)()’
foo.cpp:11:9: note: standard conversions are not allowed in this context
Edit
Though I have not fully understand what goes wrong in the above code yet. But I think there is a another way without specifically construct a SFINAE class but archive the same effect.
#include <iostream>
template <typename Derived>
class B
{
public :
void call ()
{
call_dispatch(&Derived::call);
}
template <typename C>
void call_dispatch (void (C::*) ())
{
static_cast<Derived *>(this)->call();
}
void call_dispatch (void (B<Derived>::*) ())
{
std::cout << "Call B" << std::endl;
}
private :
};
class D1 : public B<D1>
{
public :
void call ()
{
std::cout << "Call D1" << std::endl;
}
};
class D2 : public B<D2> {};
int main ()
{
D1 d1;
D2 d2;
d1.call();
d2.call();
return 0;
}
Basically, because D1 and D2 both are derived from B, so the expression &Derived::call will always be resolved. In D1 it resolved to &D1::call, then the template version member is used. In D2, it does not have its own call, so &D2::call is resolved to &B::call, and thanks to
#DavidRodríguez-dribeas, who points out that now &D2::call has the type B::call, therefore the template and the non-template members equally match, but non-template is preferred. So the default call is used.
Can help me see if there is any defect in this new code?
Where does the void (B::*)() and &B::call come from?
The type of a pointer to member is not the type on which you obtained such pointer, but the type on which the member is defined.
struct base { int x; };
struct derived : base {};
int main() {
std::cout << std::is_same< decltype(&derived::x), int (base::*) >::value << std::endl;
}
The above program prints 1. In your case, when you use &D::base, the compiler finds B<D2>::call as a member of the base template, and that is the result of the expression: void (B<D2>::*)().
Your instantiation of SFINAE is expecting the function pointer template argument to be of type void (D2::*)(), but instead is of type void (B<D2>::*)() (because call is not overidden in D2, it uses the one defined in B<D2>).
Edit
It is not the instantiation of template <typename D>
void call (SFINAE<D, &D::call> *) that is failing here. There is no substitution error there. The substitution error occurs with the instantiation of SFINAE<B<D2>, &B<D2>::call>, of which there is no fallback instantiation, hence the error.