mrwad99
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 ,Threading Model>' 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<AnotherClas s>
it all works fine.
What is the code above trying to achieve, can someone please tell me?
TIA
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
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<AnotherClas
it all works fine.
What is the code above trying to achieve, can someone please tell me?
TIA
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.
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.
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;
}
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.
>> 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.
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.
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<in t, 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
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<in
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
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>.
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;
}
>> 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.
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.
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)
Typo: type(s)
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!
>> 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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
>> 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
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> > {}
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 :)
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.
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.
ASKER
Thanks both :)
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.
Open in new window