-
September 24th, 2009, 02:43 AM
#1
Any nice way to get round the old "template typedefs are illegal" problem?
Here's a bit of context. I have a non-template class that contains a nested template class:
Code:
class A
{
public:
typedef size_t size_type;
template <typename T>
class N
{
//...
};
//...
};
The above definition is used a traits class
Code:
template <typename T, typename Class_>
struct SomeTraits
{
typedef typename Class_::template N<T> n_type;
typedef typename Class_::size_type size_type;
};
The problem is, that I also have a class B, and that class needs to contain the same nested class as class A. Ideally, what I would like to do is the following:
Code:
template <typename T>
class NCommon
{
//...
};
class A
{
public:
typedef size_t size_type;
template <typename T> typedef NCommon<T> N<T>;
//...
};
class B
{
public:
typedef size_t size_type;
template <typename T> typedef NCommon<T> N<T>;
//...
};
But that typedef is illegal. The only way round the problem that I can think of is the following:
Code:
template <typename T>
class NCommon
{
//...
protected:
~NCommon(){}
};
class A
{
public:
typedef size_t size_type;
template <typename T>
class N : public NCommon
{};
//...
};
class B
{
public:
typedef size_t size_type;
template <typename T>
class N : public NCommon
{};
//...
};
But I would rather have a more elegant solution. Any ideas/comments welcome.
-
September 24th, 2009, 06:19 AM
#2
Re: Any nice way to get round the old "template typedefs are illegal" problem?
Would declaring the template class as a friend of A and B work?
Code:
template <typename T>
class NCommon
{
//...
protected:
~NCommon(){}
};
template <typename T>
class N : public NCommon<T>
{};
class A
{
public:
typedef size_t size_type;
template <typename T>
friend class N;
//...
};
class B
{
public:
typedef size_t size_type;
template <typename T>
friend class N;
//...
};
Rich
Visual Studio 2010 Professional | Windows 7 (x64)
Ubuntu
-
September 24th, 2009, 06:57 AM
#3
Re: Any nice way to get round the old "template typedefs are illegal" problem?
That's a nice thought, but unfortunately it won't work, because the friend keyword only allows N to see the private and protected parts of classes A and B, it doesn't add N as a name within them.
The way I see it, I have three options, the first being to duplicate the code. The second being to add T as a template parameter to the class A and class B declarations - but this not only messes up the desigh, but actually ruins the semantics of the destination code. The third being to use the inheritance mechanism suggested in my prior post - but I don't like that idea since it is clearly a code fudge. Although I don't like the idea of duplicate code, in this instance I think I'll go with the duplicate code option.
Thanks for the suggestion though, I really appreciate it.
-
September 24th, 2009, 07:17 AM
#4
Re: Any nice way to get round the old "template typedefs are illegal" problem?
why do you find your "inheritance mechanism" so bad ? (I mean, it makes sense from a design point of view)
anyway, you could also try
Code:
class NCommon
{
public:
template <typename T>
class N
{
//...
};
};
class A
{
public:
static const bool forwarded = true;
typedef NCommon forwarder;
};
class B
{
public:
static const bool forwarded = true;
typedef NCommon forwarder;
};
class C
{
public:
static const bool forwarded = false;
template <typename T> class N {/*...*/};
};
template <typename T, typename Class_, bool forwarded = Class_::forwarded>
struct SomeTraits
{
typedef typename Class_::template N<T> n_type;
// typedef typename Class_::size_type size_type;
};
template <typename T, typename Class_>
struct SomeTraits<T,Class_,true>
{
typedef typename Class_::forwarder::template N<T> n_type;
// typedef typename Class_::forwarder::size_type size_type;
};
or a variation thereof.
-
September 24th, 2009, 07:48 AM
#5
Re: Any nice way to get round the old "template typedefs are illegal" problem?
If you place a kind of self identification inside NCommon would it be a solution for you?
Code:
#include <cstddef>
class A
{
public:
typedef size_t size_type;
template <typename T>
struct NCommon
{
typedef NCommon<T> Self;
};
};
class B
{
public:
typedef size_t size_type;
template <typename T>
struct NCommon
{
typedef NCommon<T> Self;
};
};
template <typename T, typename Class_>
struct SomeTraits
{
typedef typename Class_::size_type size_type;
typedef typename Class_::template NCommon<T>::Self N_type;
};
int main()
{
SomeTraits<int, A> a;
SomeTraits<int, B> b;
}
-
September 25th, 2009, 01:57 AM
#6
Re: Any nice way to get round the old "template typedefs are illegal" problem?
Originally Posted by superbonzo
why do you find your "inheritance mechanism" so bad ? (I mean, it makes sense from a design point of view)
anyway, you could also try
Code:
class NCommon
{
public:
template <typename T>
class N
{
//...
};
};
class A
{
public:
static const bool forwarded = true;
typedef NCommon forwarder;
};
class B
{
public:
static const bool forwarded = true;
typedef NCommon forwarder;
};
class C
{
public:
static const bool forwarded = false;
template <typename T> class N {/*...*/};
};
template <typename T, typename Class_, bool forwarded = Class_::forwarded>
struct SomeTraits
{
typedef typename Class_::template N<T> n_type;
// typedef typename Class_::size_type size_type;
};
template <typename T, typename Class_>
struct SomeTraits<T,Class_,true>
{
typedef typename Class_::forwarder::template N<T> n_type;
// typedef typename Class_::forwarder::size_type size_type;
};
or a variation thereof.
It's not that I find the thought of inheritance so bad, it's just I feel there has to be a better solution. I like your solution, but it adds an extra bit of indirection, that's the only qualm I have with it. Thanks for the suggestion.
-
September 25th, 2009, 02:04 AM
#7
Re: Any nice way to get round the old "template typedefs are illegal" problem?
Originally Posted by ltcmelo
If you place a kind of self identification inside NCommon would it be a solution for you?
Code:
#include <cstddef>
class A
{
public:
typedef size_t size_type;
template <typename T>
struct NCommon
{
typedef NCommon<T> Self;
};
};
class B
{
public:
typedef size_t size_type;
template <typename T>
struct NCommon
{
typedef NCommon<T> Self;
};
};
template <typename T, typename Class_>
struct SomeTraits
{
typedef typename Class_::size_type size_type;
typedef typename Class_::template NCommon<T>::Self N_type;
};
int main()
{
SomeTraits<int, A> a;
SomeTraits<int, B> b;
}
That's an interesting idea, but it doesn't solve the problem that I wish to solve, and that is to prevent the duplication of common code, whilst keeping access to class N simple through the traits class.
-
September 25th, 2009, 02:55 AM
#8
Re: Any nice way to get round the old "template typedefs are illegal" problem?
Thanks for all of your input, I have finally come to a solution - one that probably won't be obvious from my prior posts, since I didn't give you the relationship between classes A and B. The difference between class A and B, is that A specifies an interleaved data format (and how to cope with it) and B specifies a planer data format (and how to cope with it). My solution is to create a template class C with a boolean isPlaner template parameter, and also I'll define the nested class N within the template class C.
Code:
template <bool isPlaner>
class C
{
public:
void doSomething() const;
template <typename T>
class N
{
//...
}
};
I'll then specialise the functions that should behave differently, in the above case that's doSomething.
Code:
template<>
void C<true>::doSomething() const
{
//do something
}
template<>
void C<false>::doSomething() const
{
//do something else
}
That now means that A and B can be realised through the appropriate typedefs of class C.
Code:
typedef C<false> A;
typedef C<true> B;
Thanks once again for all your input.
-
September 25th, 2009, 03:31 AM
#9
Re: Any nice way to get round the old "template typedefs are illegal" problem?
ok, we were a bit out of context ! anyway, just for completeness, here is a variation of my post code using a small (but very useful) MPL facility:
Code:
class A
{
public:
typedef unsigned int size_type;
template <typename T> class N {/*...*/};
};
class B
{
public:
typedef A SameTraitsAs;
};
namespace detail {
BOOST_MPL_HAS_XXX_TRAIT_DEF( has_SameTraitsAs );
} // end - detail
template <typename T, typename Class_, bool forwarded = detail::has_SameTraitsAs<Class_>::value >
struct SomeTraits
{
typedef typename Class_::template N<T> n_type;
typedef typename Class_::size_type size_type;
};
template <typename T, typename Class_>
struct SomeTraits<T,Class_,true>
{
typedef typename Class_::SameTraitsAs::template N<T> n_type;
typedef typename Class_::SameTraitsAs::size_type size_type;
};
usage is more expressive and less redundant in this way...
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|