
From: Robert Bell <belvis@imageworks.com>
Gennadiy Rozental wrote:
Here is how I see it. Trait is something type specific, IOW specific to type, IOW uniquely defined by type. If you could provide trait along with the type as a template parameter, that mean you could change it independently from the type, IOW you could define different value for trait still using the same type. For example if you have component C defined like:
template<typename T, typename Trait> struct C { ... };
You could instantiate it like C<MyT,TraitValue1> or C<MyT,TraitValue2>. So as you could see trait value is not uniquely defined by the type.
So what? The only thing I'm getting from this as to why traits should be "uniquely defined by the type" is because you've defined traits that way. But I don't see why traits have to be defined that way. I don't see what bad thing happens if C is defined as above.
If trait is synonymous with policy, then why have both? When policies hit the scene, they were like "traits on steroids," as Andrei put it. They pushed the envelope in terms of what a traits class could be used to do. The result, however, didn't look like the traits class stuff that had been used prior to that point, save for std::char_traits in the likes of std::basic_string. As a result, I think we wound up with something new, not just a slight variation on the status quo. Thus, a traits class is one that can be specialized for various types, but is always known by one name in all uses. By contrast, a policy class is one passed as a template argument for use specifically to alter behavior according to predefined points of customization.
Proper design would be to have trait stand alone class, like this:
template<typename T> struct Trait { value = ... };
template<typename T> struct C { here we are using Trait<T>::value, where we used to use Trait. };
Now if the user needs to define trait value (or change from using default value provided by most traits designs), she just need to define explicit/partial specialization for this type or types family.
Unless, as someone else pointed out, there already exists such a specialization.
On the other hand policy is something that is orthogonal to the primary type (actually in policy based design there may not be any primary type, but just an orthogonal policies), IOW you could use different policies in conjunction with the same type. And natural place for the policy is along with type in component definition among the template parameters.
You seem to be arguing that
template<typename T, typename U = traits<T> > class Foo { };
is wrong because it blurs the distinction between traits and policies. I
I think Gennadiy would agree that this is fine because U is a policy template parameter defined to use at least a subset of traits' interface. If U isn't well-defined and traits becomes the definition of U, even though Foo doesn't use all of traits' interface, then the design of Foo is poor. That would seem to be the case with std::basic_string and std::char_traits. I haven't looked at the implementation with this in mind, but I'm guessing that std::basic_string doesn't use all of std::char_traits interface, and yet the "traits" parameter of std::basic_string isn't defined separately.
say "so what?" If the problem is best solved by blurring these ideas, blur away. No one seems to have yet been able to define "traits" and "policies" very well anyway, so what are we blurring?
*If* there is value, as I of course think there is, in maintaining a distinction for accuracy in discourse, then we're needlessly combining separate notions. If few think the distinction is important, then we should simply choose one or the other term to avoid confusion.
On 1/3/2004, you wrote
I've expressed my opinion in the matter before: Traits - as name suggest could not be policy. IOW should not be template parameters. Traits are type specific and an ability to supply them independently to the primary type in most cases leads to invalid/too complicated design.
The way I read this, your use of "most cases" means you agree there are some cases where the above use of traits passed into a template is justified and acceptable. This seems to contradict the idea above that traits can never be used this way. Can you clarify please?
If an existing traits class provides (at least) the interface needed for a template's policy class, then using the traits class as that policy should be fine. The fact that the template parameter is a policy means that the template is allowing for other implementations of that interface. That doesn't make the traits class any less the one definition of those traits. Put another way, any other classes implemented to be used as the template's policy argument won't be used as traits; they'll only be used as the template's arguments. The distinction provides some clarity when using the phrases "traits class" or "policy class." When someone says "policy class," you immediately know that they mean something passed as a template argument or the template parameter used within the template to effect behavioral changes. When someone says "traits class," you immediately know that they mean something customizable for each distinct type, but not for each template wishing to use it. Those are quite different things and disambiguiating them via different names is sensible. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;