Link to home
Start Free TrialLog in
Avatar of mrwad99
mrwad99Flag for United Kingdom of Great Britain and Northern Ireland

asked on

Template arguments and C3203 compiler error

Ah hello.

I have come across the following code, and my head is spinning trying to figure out exactly what it is trying to achieve:

template<class T,template <class> class CheckingPolicy, template <class> class ThreadingModel>
class SmartPtr : public CheckingPolicy<T>, public ThreadingModel<SmartPtr>
{
};

This is taken from http://radio.weblogs.com/0105852/stories/2002/11/19/multiparadigmDesignAndGenericProgramming.html.

VS2005 complains

error C3203: 'SmartPtr' : unspecialized class template can't be used as a template argument for template parameter '<unnamed-symbol>', expected a real type
see reference to class template instantiation 'SmartPtr<T,CheckingPolicy,ThreadingModel>' being compiled

After reading http://msdn2.microsoft.com/en-us/library/606k9xxc.aspx, I see this is the intended behaviour.

What is confusing is the fact that we are deriving from ThreadingModel<SmartPtr>, when we are only just declaring the class SmartPtr!  When I change it to

public ThreadingModel<AnotherClass>

it all works fine.

What is the code above trying to achieve, can someone please tell me?

TIA
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

CheckingPolicy and ThreadingModel are template template classes, rather than defining a concrete type they define a template that needs to be instantiated to make it a concrete type. This syntax allows you to pass a class of template to a template class for it to be instantiated within the scope of the template class.

http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=/com.ibm.vacpp6m.doc/language/ref/clrc16template_template_arguments.htm

In this instance, SmartPtr is instantiated with concrete type T and the template template class parameters CheckingPolicy and ThreadingModel. CheckingPolicy  is then instantiated with type T and ThreadingModel is being instantiated with the class of template SmartPtr. The error you are seeing is because the compiler thinks that ThreadingModel should be getting instantiated with a concrete implementation of SmartPtr and not the class of template SmartPtr. If the parameter to ThreadingModel is changed to a concrete type the code will build.

I have modified the code below to build... obviously it does nothing useful :)

-Rx.
template <typename T>
struct foo{};
 
template <typename T>
struct bar{};
 
template 
<
     class T,
     template <class> class CheckingPolicy,
     template <class> class ThreadingModel
> 
class SmartPtr : public CheckingPolicy<T>, public ThreadingModel<SmartPtr<int, foo, bar> >{};
 
int main()
{
	SmartPtr<int, foo, bar> sp = SmartPtr<int, foo, bar>();
	return 0;
}

Open in new window

Incidentally, since this code contained some fundamental syntax errors (not just the problem with the template), I'm not sure how much credence I'd give the article. If you are after reading up on this start with the Wikipedia page...

http://en.wikipedia.org/wiki/Policy-based_design

Also, try to get hold of a copy of the book Modern C++ Design by Andrei Alexandrescu.
>> What is the code above trying to achieve, can someone please tell me?
Well, it looks like it's trying to implement a policy to define what is and isn't valid for a smart pointer.
The working example below shows the crude and contrived implementation of a policy based smart pointer.

NB. gcc also rejects this code -- I'm pretty certain it's just incorrect code.

#include <stdexcept>
 
template <typename T>
struct DefaultPolicy
{
	// No checks, anything goes
	static void Check(T const * p) {}
};
 
template <typename T>
struct SpecialPolicy : DefaultPolicy<T>
{
	// Reject NULL pointers
	static void Check(T const * p)
	{
		if(NULL == p) { throw std::runtime_error("Opps, bad pointer"); }
	}
};
 
template 
<
     class T,
     template <class> class CheckingPolicy = DefaultPolicy // Set default policy
> 
class SmartPtr
{
private:
	typedef CheckingPolicy<T> Policy;
 
public:
	SmartPtr(T * p) : m_p(p)
	{
		Policy::Check(m_p);
	}
 
	~SmartPtr() { delete m_p; }
 
private:
	T * m_p;
};
 
int main()
{
	// These will all work without error
	SmartPtr<int> sp1(new int); // Create with default policy
	SmartPtr<int, SpecialPolicy> sp2(new int); // Create with special policy
	SmartPtr<int> sp3(NULL); // Create with special policy
 
	// This one throws because the policy tells it too
	SmartPtr<int, SpecialPolicy> sp4(NULL); // Create with special policy
	return 0;
}

Open in new window

Avatar of mrwad99

ASKER

Thanks for the post :)

>> Also, try to get hold of a copy of the book Modern C++ Design by Andrei Alexandrescu.

Heh, that is the very book I am working through :)  This is why I am confused, since the code I posted is in print, so I guess it is just a limitation of VS2005??

>> NB. gcc also rejects this code -- I'm pretty certain it's just incorrect code.

It is not in the errata: http://erdani.org/errata/ (I have print 7, and the code is on page 17).

OK.  Please bear with me on this:

template
<
     class T,
     template <class> class CheckingPolicy,
     template <class> class ThreadingModel

class SmartPtr : public CheckingPolicy<T>, public ThreadingModel<MyClass>{};

Here I am saying that essentially SmartPtr "is-a" (due to public inheritance) CheckingPolicy<T> *and* a ThreadingModel<MyClass>.  So it has all the functionality provided by the CheckingPolicy template class (specialised for T) and the ThreadingModel class (specialised for MyClass).

Right.

When we start to say

template
<
     class T,
     template <class> class CheckingPolicy,
     template <class> class ThreadingModel

class SmartPtr : public CheckingPolicy<T>, public ThreadingModel < SmartPtr<int, foo, bar> >{};

We are saying that SmartPtr "is-a" CheckingPolicy (specialised for T) and a ThreadingModel (specialised for SmartPtr, which in turn "is-a" CheckingPolicy (specialised for T) and a ThreadingModel (specialised for SmartPtr.....) ad infinitum.)

This apparent recursion is causing me problems understanding.

>> SmartPtr<int, foo, bar> sp = SmartPtr<int, foo, bar>();

Not sure what you are doing there.  What is the point of the assignment, and why the trailing parentheses?

Thanks.
>> This is why I am confused, since the code I posted is in print, so I guess it is just a limitation of VS2005??
Nope, the code posted just isn't valid -- it contains various syntax errors, not just the template ones. Even with these fixed both VS2005 and gcc4.1.2 reject it. I, also, can't see how it could ever work -- although I am not Andrei Alexandrescu, the God-Father of meta template programming so I am prepared to stand corrected :)

>> Here I am saying that essentially SmartPtr "is-a" (due to public inheritance) CheckingPolicy<T> *and* a ThreadingModel<MyClass>.  

Yes, and I also disagree with this model since it isn't. You'll see in my example code I dropped the inheritence. How can a smart pointer be a policy or a thread model? It doesn't make a whole deal of sense to me.

>>>> SmartPtr<int, foo, bar> sp = SmartPtr<int, foo, bar>();
>> Not sure what you are doing there.  What is the point of the assignment, and why the trailing parentheses?

Oh, sorry -- that is the correct template way to initialize things to be a default value. It is exactly the same as this

int n = int();

All we are doing is calling the default constructor, which should always return an object of a valid default state and assigning it to the object we wish to initialize. The reason we do it this way is, for example, if we wish to initialize an object of type T how do we know what is a valid value to initialize it to? We don't since we have no idea what it is therefore we use the default constructor, which will always do the right thing...

T t = T();

I am just in the habit of always initializing using this syntax for types that I don't know how to initialize safely. You'll see in my later post I know how to initialize SmartPtr so I dropped that syntax.
Avatar of mrwad99

ASKER

>> it contains various syntax errors, not just the template ones

Can you elaborate?  Or is it that the

public ThreadingModel<SmartPtr>

bit uses SmartPtr, which in itself is a template which takes three arguments?

>> You'll see in my example code I dropped the inheritence.

You posted this as your second post:

template
<
     class T,
     template <class> class CheckingPolicy,
     template <class> class ThreadingModel

class SmartPtr : public CheckingPolicy<T>, public ThreadingModel<SmartPtr<int, foo, bar> >{};

surely your use of public implies inheritance?  Or are we talking about different two examples?  In this example, how is the recursion problem I mentioned not present?

Sorry, I am sure I am just missing one fundamental bit to this, but the penny just has not dropped yet...
>> Can you elaborate?  Or is it that the
No, I mean it has real syntax errors (2); see below where I've commented them

>> You posted this as your second post
I was referring to this: http:#20947307



template 
<
     class T,
     template <class> class CheckingPolicy,
     template <class> class ThreadingModel, //<--- RX: Trailing comma
> 
class SmartPtr : public CheckingPolicy<T>. public ThreadingModel<SmartPtr> //<--- RX: Trailing dot not comma after CheckingPolicy<T>.

Open in new window

Something like this would probably be sufficient, no ?
template<class T>
class CheckingPolicy {
};
 
template<class T>
class ThreadingModel {
};
 
template<class T>
class SmartPtr : public CheckingPolicy<T>, public ThreadingModel<SmartPtr<T> > {
};
 
int main(void) {
  SmartPtr<int> ptr;
  // ...
  return 0;
}

Open in new window

>> Something like this would probably be sufficient, no ?
This doesn't allow for user define policies, which (as far as I can tell) is the point of the bit of code under discussion. You could also do this passing in a concrete policy type but the template template class solution is, to my mind, more elegant and not very hard to understand once you realize you are passing in a template and not a type.

Also, like I said above, I really don't see how a smart pointer can have an IS_A relation ship with either a policy class or a threading model class. That model just doesn't make sense to me. Can you maybe give it some context that would I8?

-Rx.
>> but the template template class solution is, to my mind, more elegant
Also, at the point where the policy is decided you may not actually know the type(2) it is going to work with.
>> type(2)
Typo: type(s)
Avatar of mrwad99

ASKER

OK.  I am still confused, and the original question still has not been answered.

>> What is confusing is the fact that we are deriving from ThreadingModel<SmartPtr>, when we are only just declaring the class SmartPtr!

Can someone *please* clarify how this is possible!
ASKER CERTIFIED SOLUTION
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>> I see it more as a "implements a certain behavior" relationship. Or more specifically
Then it has an implements_in_terms_of relationship, which should be either done by layering or private inheritance. This is exactly the same as the square is not a rectangle point I made the other day. As it stands, neither is actually necessary to implement a policy, as you can see from my example code above.

http:#20947307
Of course you're right, evilrix ... I just gave it a twist to make it easier to accept ;)
>> which should be either done by layering or private inheritance
This works just as well but also implements the correct relationship model between the super and the sub class(s)

template<class T>
class SmartPtr : private CheckingPolicy<T*>, private ThreadingModel<SmartPtr<T> > {}
>> Of course you're right, evilrix ... I just gave it a twist to make it easier to accept ;)
Fair enough -- nothing wrong with playing Devils Advocate :)
What if you change the names of the classes, like this for example :

template<class T>
class SmartPtr : public CheckedObject<T*>, public ThreadedObject<SmartPtr<T> > {};


SmartPtr is a checked object and is a threaded object. Might make it easier to digest heh.
Avatar of mrwad99

ASKER

Thanks both :)