Reputation: 8920
I wrote the following dumb policy struct:
template
<typename T>
struct SuperLeague
{
public:
void printLeague(){std::cout << "SuperLegue" << std::endl;};
protected:
//~SuperLeague(){}
};
and the host class
template
<typename TT,template <typename C> class Policy>
class League: public Policy<TT>
{
public:
void fun()
{
Policy<TT>().printLeague();
}
};
My main is
int main()
{
League<int,SuperLeague> k;
League<int,SuperLeague> kk;
k.fun();
kk.printLeague();
League<int,SuperLeague> *kkk=new League<int,SuperLeague>();
kkk->fun();
//delete kkk;
};
Until here, everything works fine. And the output is:
SuperLegue
SuperLegue
SuperLegue
In one of his Books Andrei Alexandrescu writes:
Unless the policy class defines a virtual destructor, applying delete to a pointer to the policy class has undefined behavior. He explains the reasons not to use virtual destructor on the policy or protected (or private) inheritance when deriving from the policy class, and he suggests The lightweight, effective solution that policies should use is to define a nonvirtual protected destructor. The problem is that when I tried to do that using ~SuperLeague(){}
the compiler complains that the destructor is protected. What I am doing wrong?
Upvotes: 0
Views: 576
Reputation: 126522
You shouldn't be creating a temporary policy object inside League::fun()
. Since your instance of the League
template derives from the appropriate instance of the Policy
template, it inherits the printLeague()
function:
template
<typename TT,template <typename C> class Policy>
class League: public Policy<TT>
{
public:
void fun()
{
Policy<TT>::printLeague();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
}
};
The reason why your solution won't compile when you declare the destructor protected
is that protected
makes base class members accessible from a derived class when accessing an object (or dereferencing a reference or pointer to an object) of the same derived class (League
in your case).
That is not the case in your example, where you create a temporary object of type Policy<TT>
and invoke printLeague()
on that object (which is not of type League
).
Per paragraph 11.4/1 of the C++11 Standard:
An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class (11.2). As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C. If the access is to form a pointer to member (5.3.1), the nested-name-specifier shall denote C or a class derived from C. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C.
Upvotes: 2
Reputation: 76448
Policy<TT>().printLeague();
This creates an object of type Policy<TT>
, calls printLeague()
on that object, then destroys the object. The compiler is complaining about destroying the object, because the destructor is protected.
Since Policy<TT>
is a base class, just call printLeague()
directly.
Upvotes: 1