going crazy with template function

Hi all,
This is my situation:
I've made a template class my_vector that works like normal vectors. I have a normal random access iterator and a random access that returns sorted elements(sortIterator)

template<typename T, typename F> class my_vector{...}

where T is the type of elements to be stored in my_vector, and F is a functor that determines the sorting strategy, for example ascending or descending order.

Now i need a global template funtion that checks if two my_vector objects, contains the same values, in the same amount, no matter the order.
For example:

[2,1,4,5,4,2] and [5,4,2,1,2,4] passed to this funtion will return true.

If i have two my_vectors containing different types of value, as
my_vector<char,whatever1> and my_vector<double, whatever2> the function returns false.

My idea:
- if 2 my_vector are on the same type and on the same functor (and the same size), simply call sortIterator on both and cicle them, confronting the value at each step.

- if they are on same type but different functors, create a new my_vector copying data from one and the functor from the other, so now i am in the previous condition.

- if they are on two different types, function returs false.

My first thought was: well what's the problem i'll write 3(4) different template function, one for each case and problem is solved:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//same type, same functor
template<typename T, typename F> bool check(const my_vector<T, F>& vec1,const my_vector<T, F>& vec2){
   bool same=false;
   if(vec1.size()==vec2.size(){
      my_vector<T,F>::sortIterator begin1,begin2,end1,end2;
      begin1=vec1.begin();
      beign2=vec2.begin();
      end1=vec1.end();
      end2=vec2.end();
      while(begin1!=end1 && begin2!=end2){
         if(*begin1==*begin2){
            same=true;
            begin1++;
            begin2++;
         else{
            same=false;
            begin1=end1; //to end the while
         }
      }
   }
   return same;
} 


1
2
3
4
5
6
7
8
//same type different functor
template<typename T, typename F, typename F1> bool check(const my_vector<T, F>& vec1,const my_vector<T, F1>& vec2){
   if(vec1.size()==vec2.size(){
      my_vector<T, F> vec3=vec2;
      return check(vec1,vec3);
   }
   else return false;
}


1
2
3
//different type, same functor
template<typename T, typename T1, typename F> bool check(const my_vector<T, F>& vec1,const my_vector<T1, F>& vec2){
   return false;}


1
2
3
//different type, different functor
template<typename T, typename T1, typename F, typename F1> bool check(const my_vector<T, F>& vec1,const my_vector<T1, F1>& vec2){
   return false;}


Now i can confront every my_vector, being sure each case is covered.

But is this a good solution?
Is there a way to put everything in a single function?

I've tried this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
template<typename T, typename T1, typename F, typename F1> bool check(const my_vector<T, F>& vec1,const my_vector<T1, F1>& vec2){
   bool same=false;
   if(typeid(T1)==typeid(T2)){
      if(vec1.size()==vec2.size()){
         my_vector<T1, F1> vec3=vec2; //this causes me problems compiling
                                      //***problem in detail after code*** 

	 my_vector<T1,F1>::sortedIterator begin1, end1, begin2, end2;
         begin1 = vec1.begin();
	 begin2 = vec3.begin();
	 end1 = vec1.end();
	 end2 = vec3.end();

	 while(begin1!=end1 && begin2!=end2){
	    if(*begin1==*begin2){
	       same=true;
	       begin1++;
	       begin2++;
	    }
	    else{
	       same=false;
	       begin1=end1;
	    }
	 }
   }
   return same;   
}


*** the main problem ***
Since i can create a my_vector of everything, not only int, char etc.. but also struct,array and whatever(in theory) i can't get the code to compile cause of this instruction my_vector<T1, F1> vec3=vec2, that is a call to conversion-constructor.
For example if i have:
1
2
3
4
my_vector<my_struct, my_struct_functor> vec1;
my_vector<another_random_data_type, proper_functor> vec2;

check(vec1, vec2)


it won't compile

Is there a solution?
What if i use the first method, 4 template functions?
Could anyone come to me and say "You can't do that, because you're violating this or that rule..."?
Can I create many version of the same function?
Isn't a template function supposed to cover every possible case?


Thanks
Last edited on
It is good to catch most problems at compile time, so in my opinion you shouldn't even make a check function with two different data_type template paramters which would allow comparsion for different types, which makes no sense in this case.

On the other hand, if you want to compare the two vector's elements, regardless of the ordering functor, than make a single comparing funtion which takes a single data_type template parameter and a two function template parameters (which might be happen to be the same, but we don't care, right?)

So implement only a single check() function with the following signature
template<class T, class F1, class F2>
bool check(const my_vector<T, F1>&, const my_vector<T, F2>&);
Last edited on
Thanks,
so is there no chance to return false in this case?
How can i catch this problem at compile time?
> But is this a good solution?

It is an ok solution with one caveat: specializing function templates can lead to a later situation which is unintuitive to most C++ programmers - function template specializations don't overload.
See: http://www.gotw.ca/publications/mill17.htm

As I had stated in an earlier thread, I would recommend using SFINAE instead. For brevity, this example uses standard C++ functionality.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <type_traits>
#include <algorithm>

//  if they are on two different types, function returs false.
template< typename T, typename U, typename F, typename G >
typename std::enable_if< !std::is_same<T,U>::value, bool >::type
check( const my_vector<T,F>& , const my_vector<U,G>& ) { return false ; }

// same type and on the same functor ...
template< typename T, typename U, typename F, typename G >
typename std::enable_if< std::is_same<T,U>::value && std::is_same<F,G>::value, bool >::type
check( const my_vector<T,F>& a, const my_vector<U,G>& b )
{
    if( a.size() == b.size() ) return std::equal( a.begin(), a.end(), b.begin() ) ;
    else return false ;
}

// on same type but different functors, create a new my_vector ...
template< typename T, typename U, typename F, typename G >
typename std::enable_if< std::is_same<T,U>::value && !std::is_same<F,G>::value, bool >::type
check( const my_vector<T,F>& a, const my_vector<U,G>& b )
{ return a.size() == b.size() ? check( a, my_vector<T,F>(b) ) : false ; }


Thanks!
So basically SFINAE tells the compiler which template function(in a set of overloaded template function) to exclude from the compiling process, right?

I've also read that i can define my own traits, do you know any good guideabout SFINAE and traits creation?
Because i don't know if i can use std::enable_if and std::is_same...
> So basically SFINAE tells the compiler which template function(in a set of
> overloaded template function) to exclude from the compiling process, right?

Yes. Based on failure of some substitution or the other.


> do you know any good guideabout SFINAE and traits creation?

'C++ Templates: The Complete Guide' by Vandevoorde and Josuttis http://www.amazon.com/Templates-The-Complete-Guide-ebook/dp/B003YL3OYG is excellent.

> Because i don't know if i can use std::enable_if and std::is_same

There is a minimalist home_grown::is_same<> in this thread:
http://cplusplus.com/forum/general/67727/#msg361248

A minimalist home_grown::enable_if <> would be:
1
2
3
4
5
6
namespace home_grown
{
    template< bool CONDITION, typename T > struct enable_if {} ;

    template< typename T > struct enable_if<true,T> { typedef T type ; } ;
}
Thanks! It works perfectly!
thanks
JLBorges . this is really good , i was not knowing it .
Soory for the lack of the knowledge ... @JLBorges

but , i am not able to understand this line .. what is it for , why is it used , what is the significant of it . What does it do .

typename std::enable_if< !std::is_same<T,U>::value, bool >::type
@bluecoder
For example it allows you to specialize functions for certain types:
stupid example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template < typename T >
typename std::enable_if< std::is_integral< T >::value, T >::type
reminderFrom2(T t)
{
    return t % 2;
}

template < typename T >
typename std::enable_if< std::is_floating_point< T >::value, T >::type
reminderFrom2(T t)
{
    return fmod(t, 2);
}
...
float f = 3.3f;
int i = 7;

std::cout << reminderFrom2(f) << std::endl;
std::cout << reminderFrom2(i) << std::endl;
Last edited on
@morando

thanks for the quick response .
but i am still not getting it .. as , what is the difference between

1
2
3
4
5
6
template < typename T >
typename std::enable_if< std::is_integral< T >::value, T >::type
reminderFrom2(T t)
{
    return t % 2;
}


then


1
2
3
4
5
template < typename T >
reminderFrom2(T t)
{
    return t % 2;
}


why do this line makes the difference .

typename std::enable_if< std::is_integral< T >::value, T >::type
Pass a floating point number to your function and see why.
Try to make template specialization without enable_if for my example function and see how much more lines you need to introduce to your code for it to work.


why do this line makes the difference .


if this expression std::is_integral<T>::value returns false enable_if<...>::type will not be defined so you will get a compiler error (if compiler doesn't find better function match) witch is better then runtime bug, although this is stupid example to make such mistake.

I suck at explaining things. Maybie JLBorges will come back soon and explain it better.
> why do this line makes the difference

Reading this (old) article might clarify matters:
http://drdobbs.com/cpp/184401659
thanks ..@JLBorges for the link .. now i got it .. the link have been useful
Topic archived. No new replies allowed.