An error in a method that relies on template expansion only gives a compiler error when the method is explicitly called. Though when that method is marked as virtual, it produces a compiler error whether or not it is actually called. Is there anything in the C++ standard that explains why marking these methods as virtual causes a compiler error?
#include <memory>
#include <iostream>
template <class T_>
class Foo
{
protected:
T_ data;
public:
Foo(const T_& x) : data(x) { }
Foo(T_&& x) : data(std::move(x)) { }
// comment these two lines out and it works fine.
virtual void test(T_& x) = 0;
virtual void test(T_&& x) = 0;
};
template <class T_>
class Bar : public Foo<T_>
{
public:
using Foo<T_>::Foo;
void test(T_& x)
{
std::cout << "test(&)" << std::endl;
x = this->data;
}
void test(T_&& x)
{
std::cout << "test(&&)" << std::endl;
x = std::move(this->data);
}
};
int main()
{
Bar<std::unique_ptr<int>> x(std::unique_ptr<int>(new int(42)));
}
The overriders of virtual functions are always odr-used - that is, their definition must be present, whether they are explicitly used in a translation unit or not. Overriders of virtual functions are themselves virtual ([class.virtual]/2) and all virtual functions must be defined ([basic.def.odr]/3 and 4).
Now the question is whether the test overloads in the derived class are actually instantiated.
For templates, the standard mandates that
Unless a member of a class template […] has been
explicitly instantiated or explicitly specialized, the specialization
of the member is implicitly instantiated when the specialization is
referenced in a context that requires the member definition to exist;
For virtual functions one might argue that their presence is enough to require a definition. However, the standard doesn't tie itself down and leaves the decision to the implementation, [temp.inst]/11:
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.
Making it virtual is forcing instantiation. I get the same error with the following test code after commenting out the virtual function in the base class:
int main()
{
Bar<std::unique_ptr<int>> x(std::unique_ptr<int>(new int(42)));
x.test(std::unique_ptr<int>(new int(99)));
std::unique_ptr<int> pi;
x.test(pi);
std::cout << "test returned " << *pi << std::endl;
}
The version taking an reference can't be instantiated as std::unique_ptr is not assignable.
Related
First of all, sorry for the confusing title. I have no idea how to word this properly.
The problem is not really a problem, but rather something that I don't know how to implement.
Here is the code:
#include <iostream>
class Parent
{
public:
virtual void foo()
{
std::cout << "Parent's foo" << std::endl;
}
void bar()
{
foo();
}
};
class Child : public Parent
{
public:
void foo()
{
std::cout << "Child's foo" << std::endl;
}
};
int main()
{
Child c;
c.bar();
return 0;
}
When the code above runs, it prints outChild's foo.
However the same code, BUT with the child classes foo definition beingvoid foo(bool def = true)Prints out Parent's foo.
Is there anyway to call the child's version of foo instead of the parent's one if the definitions missmatch?
Unfortunately not, if you want to add extra parameters, even default ones, you can create an overloaded function explicitly, which behaves similar in most cases to the caller.
#include <iostream>
class Parent
{
public:
virtual void foo()
{
std::cout << "Parent's foo" << std::endl;
}
void bar()
{
foo();
}
};
class Child : public Parent
{
public:
virtual void foo(bool def) // virtual if another subclass needs to override
{
std::cout << "Child's foo def = " << def << std::endl;
}
virtual void foo()override //override and virtual optional here
{
foo(true);
}
};
int main()
{
Child c;
c.bar();
c.foo();
c.foo(true);
return 0;
}
This is purely a function of when a function is overridden in C++.
In C++, function overriding is done according to the "signature" of member functions:
unqualified name
exact parameters list in the declaration (excluding implicit this)
qualification of the this implicit parameter
Obviously, by definition, the type of the this parameter cannot match exactly, as by definition the type must be a pointer to a derived class.
[Note about cv-qualification on parameters:
The parameters in the declaration as seen by caller must be exactly the same, that is after removal of meaningless cv-qualifiers on object copies: these are cv-qualifiers on local variables inside the function body, and that's only meaningful in a function definition.
void f(const int i); // takes an int by value; const is meaningless
void f(int i); // redeclaration of the same function
// redeclaration of the same function yet again
void f(const int ci) { // const is meaningful here
ci = 1; // error
}
--end note]
However the same code, BUT with the child classes foo definition
being void foo(bool def = true) Prints out Parent's foo.
Because there is no match of the parameters lists: an empty parameter list is only matched by an empty parameter list.
You need to replace the default argument with two overloaded functions here, with no forwarding to the other:
void foo(bool def); // new function signature
void foo() { // overrides Parent's member
foo(true);
}
With long complex a parameters list, it's easy to change a type and create a new function signature instead of overriding a base class virtual function; it's also easy to get the capitalisation wrong or spelling wrong (think English vs. US spelling). In general, getting the name of a function wrong (or any other name: of a type, of a template, of a variable...) causes a compilation error because that name with the small spelling change wasn't declared. But with a raw declaration of a member with the intent of overriding a base class declaration, there is no hint that you tried to do that and the compiler will not warn you (it might warn for hiding a base class declaration, but this is different). Explicitly marking a declaration intended to be an override with the virtual keyword doesn't help, introducing a new virtual function isn't the intent.
That was the sad state of affairs after the first version of the C++ standard was formalized. Now it's different.
If you want to be sure that you are indeed overriding a base class declaration, you can now use the override keyword:
class Child : public Parent
{
public:
void foo(bool def);
void foo() override {
foo(true);
}
};
Is it possible to acces a member of a derived class using a pointer to the base class?
// Example program
#include <iostream>
#include <vector>
#include <memory>
#include <string>
class A {
public:
std::string x = "this is the wrong x\n";
};
template <class T>
class B : public A {
public:
T x;
};
int main()
{
std::vector<std::unique_ptr<A>> vector;
auto i = std::make_unique<B<int>>();
i->x = 6;
vector.push_back(std::move(i));
for(auto &element : vector){
std::cout << element->x;
}
}
Here I'm always getting the output from class A. I cannot typecast it because I don't know whether the element is of type A or type B in advance. Is there a proper way to do this?
The proper way would be to make a virtual function to perform the task like printing.
class A {
public:
std::string x = "this is the wrong x\n";
virtual ~A() = default;
virtual void print() const { std::cout << x; }
};
template <class T>
class B : public A {
public:
T x;
virtual void print() const override { std::cout << x; }
};
int main()
{
std::vector<std::unique_ptr<A>> vector;
auto i = std::make_unique<B<int>>();
i->x = 6;
vector.push_back(std::move(i));
for(auto &element : vector){
element->print();
}
}
If you have a pointer to a base class, you can only access things defined on that base class (without typecasting). For all the compiler knows, it is an instance of the base class and has nothing else.
Polymorphic behavior involves using virtual functions - derived classes can change which function is called when invoking a virtual function of the base class. Note that this mechanism does not exist for members (what would you change about a member? There's only the type, and changing that in a derived class makes no sense). So the only meaningful thing you can do with pointers to base classes that should have customized behavior is to call their virtual functions.
Now, you could think "ok, I'll just make access to x go through a virtual function", but the problem here is that you must specify the involved types when you declare the virtual function in the base class already. That makes sense: The compiler needs to know which types a function involves, even a virtual one. You may only pass and return different types in the overriding functions if they are "compatible" - see covariance and contravariance for more information.
So unless all your T are covariant, virtual functions cannot help you either.
The core flaw with your concept is that you want to have some type (i.e. element->x) in a non-templated function depend on the dynamic type of some object (i.e. element). That is impossible because the compiler must know the type of each expression at compile-time. So you must approach your problem differently.
This question already has answers here:
Derived template-class access to base-class member-data
(3 answers)
Closed 8 years ago.
A coworker asked me today about code which looks somewhat like this:
#include <iostream>
template <class T>
class IBase {
public:
virtual ~IBase() {}
public:
virtual void foo() = 0;
};
template <class T>
class Base : public IBase<T> {
public:
virtual void bar() {
foo(); // compiler error
}
};
class Derived : public Base<int> {
public:
virtual void foo() {
std::cout << "Hello World!\n";
}
};
int main() {
Derived d;
d.bar();
}
At first he was getting a compiler error saying that "foo()" was not found. OK, so he tried to change it to IBase<T>::foo();. While that compiled, it resulting in a linker error. So immediately, I recalled that I've seen this type of problem before and suggesting that he write this->foo(); instead. Viola! problem solved!
Then he asked me why didn't plain foo(); work? Isn't this->x(); essentially the same as x();? Honestly, I have no idea, but he piqued my interest. So here we are:
In summary:
virtual void bar() {
this->foo(); // works
//IBase<T>::foo(); // linker error
//foo(); // compiler error
}
The question is why is this-> required. And why won't the other options work?
Because the base class member is a dependent name - its meaning depends on the template parameter, and so isn't known until the template is instantiated. The name isn't looked up in the generic IBase template, since that might be specialised to give it a different meaning before instantiation.
Qualifying it with IBase<T>:: calls the base-class function non-virtually; that's generally not what you want, especially if (as here) it's a pure virtual function with no implementation. Hence the linker error when you tried that.
Qualifying it with this-> tells the compiler that it's a member, and any further checking is deferred until the template is instantiated. The function is still called virtually.
Imagine you are the compiler. You have just been reading through and compiling the code and now you have reached the bar function. In this function, you see that there is an attempt to do foo(). At this point, do you know what foo is? You don't. It could come from the base class, but you can't possibly know, because you don't know what T is yet. It's certainly possible that there might be a specialization of IBase for which foo is something else entirely.
When you stick this-> before the function call, it causes the compiler to treat it as a dependent name. That means the compiler will say "Okay, this depends on the type of this, which I do not know yet. I'll wait until later, when I know how the class is being instantiated, before I look for foo."
IBase<T>::foo(); gives a linker error because there simply is no definition for foo in IBase<T>.
#include <iostream>
template <class T>
class IBase {
public:
virtual ~IBase() {}
public:
virtual void foo() = 0;
};
int foo() { std::cout << "hello!\n"; }
template <class T>
class Base : public IBase<T> {
public:
virtual void bar() {
foo(); // which foo?!
}
};
template <>
class IBase<int> {
public:
virtual ~IBase() {}
//virtual void foo() = 0; -- no foo()!
};
class Derived : public Base<int> {
public:
virtual void foo() {
std::cout << "Hello World!\n";
}
};
int main() {
Derived d;
d.bar();
}
The above illustrates why C++ does not allow members of dependent type parents to be implicitly found.
When you call foo() in Base, which foo() should be called? The one in IBase<T> or the free function foo()?
Either we put the decision off until later, or we go with the free function foo().
If we only go with the free function foo() if one is visible, then subtle changes in #include order can massively change what your program does. So if it should call the free function foo(), it must error if one is not found, or we are completely screwed.
If we defer the decision until later, it means less of the template can be parsed and understood until a later date. This moves more errors to the point of instantiation. It also results in some surprising behavior, like in the above case, where someone might think "I'm calling the method foo()", but actually ends up calling the free function foo() with no diagnostic.
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.