Doubt with the template instantiation problem in the below snippet of a user defined class [duplicate]
Couldn't find anything relevant in forums So ,Please help me with this code .I'm brushing up my c++ concepts and met with a strange error
#include<iostream>
using namespace std ;
class base
{
int i ;
public:
virtual void f(){cout<<"base" ; return ;};
};
class derived: public base
{
int j ;
public:
void f() {cout<<"derived" ; return ;}
};
template<class T>
class test
{
public:
test(T b)
{
b.f(); cout<<endl<<" "<<sizeof(b)<<endl;
}
};
int main()
{
base b ;
derived d;
test<derived> t(b); // cannot instantiate user defined type without typename
}
The following code fails to compile with the following error :
test.cpp: In function ‘int main()’:
test.cpp:28: error: no matching function for call to ‘test<derived>::test(base&)’
test.cpp:19: note: candidates are: test<T>::test(T) [with T = derived]
test.cpp:17: note: test<derived>::test(const test<derived>&)
I can make wild guess and arrive at an answer at to why did this happen .If i instantiate a new base class from the template , everything works just fine , but not this one . Can somebody tell me a good source for template instantiations and what are the rules/semantics , what is happening behind the curtain ? thanks
Your test snippet effectively defines this:
test::test(derived&)
As the error says, you're trying to invoke this instead:
test::test(base&)
If i instantiate a new base class from the template , everything works just fine.
Similarly, I'm sure, if you passed "d" instead of "b", everything would also work fine.
You should be able to reproduce the same scenario without templates: just defined a member function that takes "derived" as an argument, and see what happens :)
base
is not a complete derived
type, so you'll have to provide a constructor inside your template that fills in the missing details.
template<class T> //original template
class test
{
public:
test(T b)
{
b.f();
cout<<endl<<" "<<sizeof(b)<<endl;
}
};
When you create an instance of this template based on derived
, the compiler translates it to a class, which essentially boils down to this
class derivedtest
{
public:
derivedtest(derived b)
{
b.f();
cout<<endl<<" "<<sizeof(b)<<endl;
}
};
The default constructor is not generated any more. However, a default copy constructor is still created.
derivedtest::derivedtest(derived const&);
As you can see, there is no way to pass base (by reference or copy) into the class.
The solution is to provide a constructor inside your template that fills in the missing details:
template<class T>
class test
{
public:
test(base const& item)
: base(item)
{
}
test(T b)
{
b.f();
cout<<endl<<" "<<sizeof(b)<<endl;
}
};
By the way, your base
should most likely have a virtual destructor
and test(T b)
should be test(T const& b)
精彩评论