Please take a look at the following code:
template <typename T, typename Enable = void>
class A
{
public:
enum { value = 0 };
};
template <typename T>
class A<T, typename T::Enable>
{
public:
enum { value = 1 };
};
class B
{
public:
typedef void Enable;
};
class C
{
};
int main(int argc, char *argv[])
{
int b = A<B>::value; // should be 1
int c = A<C>::value; // should be 0
return 0;
}
The goal here was to create a class template called A in a way that
A<T>::value is 1 if T::Enable exists, and 0 otherwise. I've tried this
on MSVC++ 7.1, and it actually works, but only if T::Enable is exactly
the same type as the default value of the Enable template argument of
A. For example, if I change the typedef in B to
typedef int Enable; // int instead of void
then the value of variable b in main will be 0.
I'd like to know why's that. I thought that the specialization would be
a better match for all types where T::Enable exists, regardless of what
type it actually means. And I can't really see the connection with the
second template argument.
Imre 13 1945
Imre wrote: Please take a look at the following code:
template <typename T, typename Enable = void> class A { public: enum { value = 0 }; };
template <typename T> class A<T, typename T::Enable> { public: enum { value = 1 }; };
class B { public: typedef void Enable; };
class C { };
int main(int argc, char *argv[]) { int b = A<B>::value; // should be 1 int c = A<C>::value; // should be 0 return 0; }
The goal here was to create a class template called A in a way that A<T>::value is 1 if T::Enable exists, and 0 otherwise. I've tried
this on MSVC++ 7.1, and it actually works, but only if T::Enable is
exactly the same type as the default value of the Enable template argument of A. For example, if I change the typedef in B to typedef int Enable; // int instead of void then the value of variable b in main will be 0.
I'd like to know why's that. I thought that the specialization would
be a better match for all types where T::Enable exists, regardless of
what type it actually means. And I can't really see the connection with
the second template argument.
Imre
I'm guessing what you really want is a "trait":
.. #include <iostream>
..
.. template <typename T>
.. class Trait
.. {
.. public:
.. enum { ENABLE = 0 };
.. };
This defines a trait, by default it is zero. Now you can define your
'A' class like this:
.. template <typename T, typename T2 = Trait<T> >
.. class A
.. {
.. public:
.. enum { value = T2::ENABLE };
.. };
This gets 'value' from the 'ENABLE' enum in your Trait class (which is
zero by default). Now you can create your other classes:
.. class B { };
.. class C { };
Now, specialise Trait<T> so that 'ENABLE' is set to one for class 'B':
.. template <>
.. class Trait<B>
.. {
.. public:
.. enum { ENABLE = 1 };
.. };
This means that 'B' is now enabled for whatever you want to do in 'A'.
.. int main(int argc, char *argv[])
.. {
.. int b = A<B>::value; // should be 1
.. int c = A<C>::value; // should be 0
..
.. std::cout << b << " " << c << std::endl;
..
.. return 0;
.. }
This should print out "1 0" (as expected).
Hope this helps,
-shez-
I think it is possible that you are confusing default template
parameters with with partial template specialization.
If you look at your code above, neither of the lines: int b = A<B>::value; // should be 1 int c = A<C>::value; // should be 0
explicitly supplies the 'Enable' parameter of your original template.
For that reason, you have implicitly written:
int b = A<B, void>::value;
int c = A<C, void>::value;
In other words, in both cases, your second template parameter is of
type void.
This means that when the compiler is deciding whether or not to use the
partial template specialization:
template <typename T> class A<T, typename T::Enable> { public: enum { value = 1 }; };
that T::Enable must be of type void in order to the specialization to
be chosen.
If you write:
class B
{
public:
typedef int Enable;
};
then the implicitly written line:
int b = A<B, void>::value;
does not use the partial template specialization:
template <typename T> class A<T, typename T::Enable> { public: enum { value = 1 }; };
because T::Enable (really B::Enable) is of type int, and the second
parameter of A<B, void> is of type void. In other words, since void is
the type of the second template parameter, a T::Enable of type int
cannot be applied, and the specialization cannot be chosen because of
the type conflict.
I hope this helps! =)
Michael Loritsch
Shezan Baig wrote: This defines a trait, by default it is zero. Now you can define your 'A' class like this:
. template <typename T, typename T2 = Trait<T> > . class A . { . public: . enum { value = T2::ENABLE }; . };
Also, if you want to have a separate specialisation for ENABLE = 1 (as
in your original post), you can do this:
.. template <typename T,
.. typename T2 = Trait<T>,
.. int ENABLE = T2::ENABLE >
.. class A
.. {
.. public:
.. enum { value = 0 };
.. };
..
.. template <typename T, typename T2>
.. class A<T, T2, 1>
.. {
.. public:
.. enum { value = 1 };
.. };
This will give you the compile-time polymorphism I think you were
looking for in your original post.
Hope this helps,
-shez- ri***@hotmail.com wrote: I think it is possible that you are confusing default template parameters with with partial template specialization.
If you look at your code above, neither of the lines:
int b = A<B>::value; // should be 1 int c = A<C>::value; // should be 0
explicitly supplies the 'Enable' parameter of your original template.
For that reason, you have implicitly written:
int b = A<B, void>::value; int c = A<C, void>::value;
In other words, in both cases, your second template parameter is of type void.
Ah, I see. From this point on, everything makes perfect sense. Somehow
I thought that the compiler would first look for specializations
(before binding the default value to the second argument), and then,
having found the specialization, deduce the second argument instead of
using the default one. Well, I was wrong.
So it seems that I'll have to provide some more information about why I
originally started to play with this.
I plan to use some hierarchy-wide traits, as presented by A.
Alexandrescu at http://www.moderncppdesign.com/publi..._steroids.html.
Basically it looks like this:
template <class HierarchyId>
class HierarchyTraits
{
... most general traits here ...
};
template <class T>
class Traits
: public HierarchyTraits<T::HierarchyId>
{
// empty body - inherits all symbols from base class
};
Now if a root class of a class hierarchy has a nested class called
HierarchyId, you can specialize HierarchyTraits for Root::HierarchyId,
which is in effect the same as if you'd specialize Traits for all
descendants of Root. You can, of course, also directly specialize
Traits for specific types.
My problem with this solution is that the default implementation of
Traits explicitly references T::HierarchyId, thus cannot be used for
types that don't have the nested class HierarchyId. And that's exactly
what I would need. I'd like to have a default implementation that
doesn't need HierarchyId, and then have a specialization that should be
used for all types that do have HierarchyId. Only the specialization
would inherit from HierarchyTraits<T::HierarchyId>. The code in my
original post was an attempt to do this, but as you can see, I just
don't know enough about templates to get it right.
So how can it be done?
And thanks for all the answers so far.
Imre
Imre wrote: My problem with this solution is that the default implementation of Traits explicitly references T::HierarchyId, thus cannot be used for types that don't have the nested class HierarchyId. And that's
exactly what I would need. I'd like to have a default implementation that doesn't need HierarchyId, and then have a specialization that should
be used for all types that do have HierarchyId. Only the specialization would inherit from HierarchyTraits<T::HierarchyId>. The code in my original post was an attempt to do this, but as you can see, I just don't know enough about templates to get it right.
So how can it be done?
The solution I posted earlier does something like this. It has a
default trait, and you can specialise the trait as your wish for
whatever class you want.
Hope this helps,
-shez-
Shezan Baig wrote: Imre wrote: The solution I posted earlier does something like this. It has a default trait, and you can specialise the trait as your wish for whatever class you want. Ok, but how do I specialize it for a whole (possibly big) class hierarchy at once? I don't want to create a separate specialization
forall subclasses. There's a lot of them, and all these specializations would be exactly the same.
Ahh, I see. Sorry, I misread your earlier post. I'm not aware of how
we can generalise this. The best I can come up with now is to use a
macro:
.. #define ENABLE_TRAIT(T) \
.. template <> \
.. class Trait<B> \
.. { \
.. public: \
.. enum { ENABLE = 1 }; \
.. }; \
Now you just need to do:
ENABLE_TRAIT(B)
ENABLE_TRAIT(SomeClassThatDerivesFromB)
This is the best I can think of now. It's only one line per class, so
I don't think it will be *that* bad :)
Hope this helps,
-shez-
Shezan Baig wrote: Shezan Baig wrote: Imre wrote: The solution I posted earlier does something like this. It has a default trait, and you can specialise the trait as your wish for whatever class you want. Ok, but how do I specialize it for a whole (possibly big) class hierarchy at once? I don't want to create a separate specialization forall subclasses. There's a lot of them, and all these specializations would be exactly the same.
Ahh, I see. Sorry, I misread your earlier post. I'm not aware of
how we can generalise this. The best I can come up with now is to use a macro:
. #define ENABLE_TRAIT(T) \ . template <> \ . class Trait<B> \
This should, of course, read:
.. class Trait<T>
. { \ . public: \ . enum { ENABLE = 1 }; \ . }; \
Now you just need to do:
ENABLE_TRAIT(B) ENABLE_TRAIT(SomeClassThatDerivesFromB)
This is the best I can think of now. It's only one line per class,
so I don't think it will be *that* bad :)
Hope this helps, -shez-
> My problem with this solution is that the default implementation of Traits explicitly references T::HierarchyId, thus cannot be used for types that don't have the nested class HierarchyId. And that's
exactly what I would need. I'd like to have a default implementation that doesn't need HierarchyId, and then have a specialization that should
be used for all types that do have HierarchyId. Only the specialization would inherit from HierarchyTraits<T::HierarchyId>. The code in my original post was an attempt to do this, but as you can see, I just don't know enough about templates to get it right.
So how can it be done?
Well, okay, it's actually not that difficult. My problem was that I
wanted to specialize Traits for every types where T::HierarchyId
exists, whatever HierarchyId really is. Unfortunately, whatever is not
that easy to match. The solution is simply to put a typedef inside the
nested HierarchyId class, and specialize Traits based on the type value
of that typedef, insted of HierarchyId itself.
Imre
Imre wrote: My problem with this solution is that the default implementation of Traits explicitly references T::HierarchyId, thus cannot be used
for types that don't have the nested class HierarchyId. And that's exactly what I would need. I'd like to have a default implementation that doesn't need HierarchyId, and then have a specialization that
should be used for all types that do have HierarchyId. Only the
specialization would inherit from HierarchyTraits<T::HierarchyId>. The code in my original post was an attempt to do this, but as you can see, I just don't know enough about templates to get it right.
So how can it be done?
Well, okay, it's actually not that difficult. My problem was that I wanted to specialize Traits for every types where T::HierarchyId exists, whatever HierarchyId really is. Unfortunately, whatever is
not that easy to match. The solution is simply to put a typedef inside
the nested HierarchyId class, and specialize Traits based on the type
value of that typedef, insted of HierarchyId itself.
Imre
Hi Imre,
I'm not sure I quite follow you. Can you post some code to demonstrate
this?
Thanks!
-shez-
> I'm not sure I quite follow you. Can you post some code to
demonstrate this?
Sure.
template <typename T, typename Enable = void>
struct Traits
{
enum { value = 0 };
};
template <typename HierarchyId>
struct HierarchyTraits
{
};
template <typename T>
struct Traits<T, typename T::HierarchyId::Exists>:
public HierarchyTraits<typename T::HierarchyId>
{
};
/*
Now let's create a class and specialize Traits for it and all its
subclasses:
*/
class B
{
public:
class HierarchyId
{
typedef void Exists;
};
};
template <>
struct HierarchyTraits<B::HierarchyId>
{
enum { value = 1 };
};
/*
Now some subclasses of B. D1 defines its own subtree inside the class
hierarchy tree, with a different specialization of Traits. D2 just
uses B's version.
*/
class D1: public B
{
public:
class HierarchyId
{
typedef void Exists;
};
};
template <>
struct HierarchyTraits<D1::HierarchyId>
{
enum { value = 2 };
};
class D2: public B
{
};
/*
Let's also have a class that is not part of any hierarchies.
*/
class C
{
};
int main(int argc, char *argv[])
{
int b = Traits<B>::value;
int c = Traits<C>::value;
int d1 = Traits<D1>::value;
int d2 = Traits<D2>::value;
int i = Traits<int>::value;
return 0;
}
b and d2 should be 1 (value inherited from the HierarchyTraits
specialization we created for B::HierarchyId), d2 is 2 (D2's own
hierarchy specialization), c and i should be 0 (default, cause they
have no HierarchyId).
Actually that was all I wanted: to use hierarchy-wide traits while also
providing some defaults for types that are not part of any defined
hierarchies.
Imre
What compiler are you using? I am getting the following errors (using
Sun CC):
"test_heirarchytraits.cpp", line 18: Error: HierarchyId is not a member
of C.
"test_heirarchytraits.cpp", line 85: Where: While specializing
"Traits<C, void>".
"test_heirarchytraits.cpp", line 85: Where: Specialized in
non-template code.
"test_heirarchytraits.cpp", line 85: Error: value is not a member of
Traits<C, void>.
"test_heirarchytraits.cpp", line 18: Error: T is not a namespace or
class name.
"test_heirarchytraits.cpp", line 88: Where: While specializing
"Traits<int, void>".
"test_heirarchytraits.cpp", line 88: Where: Specialized in
non-template code.
"test_heirarchytraits.cpp", line 18: Error: HierarchyId is not defined.
"test_heirarchytraits.cpp", line 88: Where: While specializing
"Traits<int, void>".
"test_heirarchytraits.cpp", line 88: Where: Specialized in
non-template code.
"test_heirarchytraits.cpp", line 88: Error: value is not a member of
Traits<int, void>.
5 Error(s) detected.
Shezan Baig wrote: What compiler are you using? I am getting the following errors
(using Sun CC):
I've originally written it using MSVC++ 7.1.
Now I also tried it with gcc 3.4.3. Gcc didn't compile it at first, but
only because the Exists typedefs were private inside the HierarchyId
classes. After I've added public:, it compiled and worked well.
"test_heirarchytraits.cpp", line 18: Error: HierarchyId is not a
member of C. "test_heirarchytraits.cpp", line 85: Where: While specializing "Traits<C, void>". "test_heirarchytraits.cpp", line 85: Where: Specialized in non-template code. "test_heirarchytraits.cpp", line 85: Error: value is not a member of Traits<C, void>. "test_heirarchytraits.cpp", line 18: Error: T is not a namespace or class name. "test_heirarchytraits.cpp", line 88: Where: While specializing "Traits<int, void>". "test_heirarchytraits.cpp", line 88: Where: Specialized in non-template code. "test_heirarchytraits.cpp", line 18: Error: HierarchyId is not
defined. "test_heirarchytraits.cpp", line 88: Where: While specializing "Traits<int, void>". "test_heirarchytraits.cpp", line 88: Where: Specialized in non-template code. "test_heirarchytraits.cpp", line 88: Error: value is not a member of Traits<int, void>. 5 Error(s) detected.
Imre wrote: Shezan Baig wrote: What compiler are you using? I am getting the following errors (using Sun CC):
I've originally written it using MSVC++ 7.1. Now I also tried it with gcc 3.4.3. Gcc didn't compile it at first,
but only because the Exists typedefs were private inside the HierarchyId classes. After I've added public:, it compiled and worked well.
Cool. I haven't got that version on me right now, but thanks!
-shez- This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Valeriu Catina |
last post by:
Hi,
given the next code:
#define ENUM_CAST(x) int(x)
template<class T,int N>
class Array
{
|
by: CoolPint |
last post by:
Can anyone explain how I can make the following function accept an
default arguement for the last parameter, which should be an optional
functor?
template <typename T, typename FUNCTOR>
void...
|
by: marco |
last post by:
the problem:
I use a typedef inside a class template, than I use this type
(dim_v<N1>::Type) to define the argument of a template function f
but when I call this function from main, the compiler...
|
by: Capstar |
last post by:
Hi NG,
I am trying to get the attached piece of code to work, but I can't
figure out what I'm doing wrong. To me it seems that when I don't pass
an argument to x::do_something, it should use the...
|
by: George |
last post by:
Dear All,
I'm compiling the code below with IBM's xlC 6.0 and get the message,
"rmspace.cpp", line 34.48: 1540-0298 (S) Template argument deduction
cannot be performed using the function...
|
by: Tomás |
last post by:
Let's say we have a variable length argument list function like so:
unsigned GetAverage(unsigned a, unsigned b, ...);
I wonder does the compiler go through the code looking for invocations of...
|
by: aiooua |
last post by:
Any idea why the following code does not compile?
----
#include<iostream>
#include<list>
using namespace std;
class Base {
public:
int val;
|
by: petschy |
last post by:
hello,
i've run into an error when qualifying a copy ctor 'explicit'. the
strange thing is that i get a compiler error only if the class is a
template and declare the variable as X<Zx = y....
|
by: krishnaroskin |
last post by:
Hey all,
I've been running into a problem with default values to template'd
functions. I've boiled down my problem to this simple example code:
#include<iostream>
using namespace std;
//...
|
by: DJRhino |
last post by:
Was curious if anyone else was having this same issue or not....
I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 4 Oct 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM)
The start time is equivalent to 19:00 (7PM) in Central...
|
by: Aliciasmith |
last post by:
In an age dominated by smartphones, having a mobile app for your business is no longer an option; it's a necessity. Whether you're a startup or an established enterprise, finding the right mobile app...
|
by: NeoPa |
last post by:
Hello everyone.
I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report).
I know it can be done by selecting :...
|
by: NeoPa |
last post by:
Introduction
For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM)
Please note that the UK and Europe revert to winter time on...
|
by: nia12 |
last post by:
Hi there,
I am very new to Access so apologies if any of this is obvious/not clear.
I am creating a data collection tool for health care employees to complete. It consists of a number of...
|
by: isladogs |
last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM).
In this month's session, Mike...
|
by: GKJR |
last post by:
Does anyone have a recommendation to build a standalone application to replace an Access database? I have my bookkeeping software I developed in Access that I would like to make available to other...
| |