C++ Template Specialisation Problem

Write here if you have problems with your C++ source code

Moderator: Board moderators

Post Reply
Schultz
New poster
Posts: 13
Joined: Wed May 16, 2007 12:39 am

C++ Template Specialisation Problem

Post by Schultz »

I have been programming in C++ for a long time, but recently I stepped in a difficult problem with the language.

I have defined a type trait for to be used with a type defined as an inner class, but could not specialise the template of the trait.

The code below is my problem in its simplest form. It has been tested with gcc 4 (gentoo linux) and a gcc 3 (latest MinGW). It should not compile, just yield an error indicating the type. My intention was that it returned true_type in the compiler's error messages, but it returns false_type.

Code: Select all

struct	false_type {};
struct	true_type {};

template<typename T>	struct	trait {
	typedef		false_type		value;
};

template<typename T>	struct	X {
	struct	Y {
	};
};

template<typename T>	struct	trait< X<T> > {
	typedef		true_type		value;
};

//template<>
template<typename T>	struct	trait< typename X<T>::Y > {
	typedef		true_type		value;
};

int	main() {

	trait< X<int>::Y >::value::error_member;

	return	0;
}

Removing or leaving the template in the comment changes nothing.

Can anyone please help me? This is getting to be the bottleneck in my projects.

I know this is not the most appropriate place to post this, but I could find nowhere else.

Thanks in advance.

maxdiver
Learning poster
Posts: 51
Joined: Tue Sep 04, 2007 2:12 pm
Location: Russia, Saratov
Contact:

Post by maxdiver »

I think, one of the template specializations is not correct:
template<typename T> struct trait< typename X<T>::Y > {
typedef true_type value;
};
First of all, I could not understand it.
Secondly, my VC 2005 SP1 could not understand it too ;)
error C2764: 'T' : template parameter not used or deducible in partial specialization 'trait<X<T>::Y>'

Really, what do you mean in "typename X<T>::Y"?
You tried to use this in such way:
trait< X<int>::Y >

But, in common case "trait<TT>", how compiler can check, if TT is X<T>::Y or not? Should compiler brute all types T, or maybe should it search a path in graph? :)

Schultz
New poster
Posts: 13
Joined: Wed May 16, 2007 12:39 am

Post by Schultz »

I think, one of the template specializations is not correct:

Code: Select all

template<typename T> struct trait< typename X<T>::Y > {
        typedef true_type value;
}; 
This is the one I am not sure about. Nevertheless, it compiles with no warnings in my gcc 4. Microsoft's compiler is known for getting nothing right when it comes to more complex codes, so I am willing to retain compatibility with gcc.
error C2764: 'T' : template parameter not used or deducible in partial specialization 'trait<X<T>::Y>'
I guess this can be the source of the problem. It says the specialization could not be deduced. But why? How am I to implement this specialization then?
Really, what do you mean in "typename X<T>::Y"?
It is standard syntax. When using scopes ( :: ) within templates to access types, a typename should be placed before the clause. The compiler complains of the absence of this keyword in many cases.
But, in common case "trait<TT>", how compiler can check, if TT is X<T>::Y or not? Should compiler brute all types T, or maybe should it search a path in graph?
I know nothing of compiler implementations, but I get fascinated by how nice is the C++ metaprogramming system (printing prime lists in compiler error mesages). The metaprogramming system is Turing complete.

maxdiver
Learning poster
Posts: 51
Joined: Tue Sep 04, 2007 2:12 pm
Location: Russia, Saratov
Contact:

Post by maxdiver »

Of course, you may program C++ and don't matter about compiler implementation ;)

But let's try to think logically.
Here:
typename X<T>::Y
How compiler should choose T? There is no explicit way to choose T. Imagine this situation: you write Y, and there are several specializations of structure X, some of which contain Y, and some don't contain Y. What can compiler do in this situation? Of course, nothing.

I tried to explain, to prove, that type "T" is really not deducible.

P.S. I also don't rely on Microsoft compiler, as well as on other compiler. I tried to think logically, following Standard.

Schultz
New poster
Posts: 13
Joined: Wed May 16, 2007 12:39 am

Post by Schultz »

Oh, I got it. You mean X<int>::Y is the same as X<float>::Y.

But what if I put something like typedef T type; inside Y? Then I should be able to solve this.

The problem is that I can not get this working even then.

maxdiver
Learning poster
Posts: 51
Joined: Tue Sep 04, 2007 2:12 pm
Location: Russia, Saratov
Contact:

Post by maxdiver »

I can't understand your idea, why you want to use this construction.

I found only two solutions, but both of them are not very good:
1) specialize traits<X<T>::Y> for each T manually
2) declare another traits_X<>:

Code: Select all

template<typename T>   struct   trait_X  { 
   typedef      typename X<T>::Y        Y; 
   typedef      true_type      value; 
}; 

int   main() { 
   trait_X< X<int>::Y >::value::error_member; 
   return   0; 
}

It seems to me, that there are no other ways. Because you can't specialize template (traits<>) as another template (traits< X<T>::Y >).


The only advice I can make - change structure of your program.

Schultz
New poster
Posts: 13
Joined: Wed May 16, 2007 12:39 am

Post by Schultz »

My goal in this construct is metaprogramming. For instance, I could define integral types as those whose members are either machine types or integral types and do not have default constructors or destructors implemented.

Then, instead of trait, I could name the template pointed_value_is_integral.

Then I could specialize algorithms like:

Code: Select all

// optimised copy

// general case
template<typename I, typename T> inline void __copy(I a, I b, I c, T) {
    for (; a != c; ++a, ++c) *a = *c;
}

// integral pointers
template<typename T> inline void __copy(T* a, T* b, T* c, true_type) {
    memcpy(a, c, (b-a)*sizeof(T));
}

// user
template<typename I> inline void copy(I a, I b, I c) {
    __copy(a, b, c, typename pointed_value_is_integral<T>::value());
}
This is why this is so essential.

Krzysztof Duleba
Guru
Posts: 584
Joined: Thu Jun 19, 2003 3:48 am
Location: Sanok, Poland
Contact:

Post by Krzysztof Duleba »

There's no way to tell user-defined types from built-ins in templates except by explicit specialization.
For millions of years, mankind lived just like the animals. Then something happened which unleashed the power of our imagination. We learned to talk and we learned to listen...

maxdiver
Learning poster
Posts: 51
Joined: Tue Sep 04, 2007 2:12 pm
Location: Russia, Saratov
Contact:

Post by maxdiver »

OK. So you need template "pointed_value_is_integral".

As Krzysztof Duleba said, there is only one way - explicit initialization.

I can only present the case: I found just the same template (I've forgotten its name) in STL of Microsoft compiler, and it was implemented by explicit specialization.

Something like that:

Code: Select all

template <typename T>
bool pointed_value_is_integral (const T & right)
{
	return true;
}

template <>
bool pointed_value_is_integral (const signed int & right)
{
	return false;
}

template <>
bool pointed_value_is_integral (const unsigned int & right)
{
	return false;
}

template <>
bool pointed_value_is_integral (const signed long & right)
{
	return false;
}

...

Schultz
New poster
Posts: 13
Joined: Wed May 16, 2007 12:39 am

Post by Schultz »

I see.

So I will have to change my approach.

Thanks guys. I'll tell if I can figure ou a solution for this.

Post Reply

Return to “C++”