Skip to main content
gamedev.net
🔒 Locked

Conditional templates

Started by Kest Aug 13, 2006 at 7:03 AM 6 replies 850+ views
Original Post
Kest
Kest
Very quick simple question. Is it possible to 'ask' the compiler if a template type has a specific function, and generate different code if it does? Example:
template <typename type>
void SaveObject(const type &obj,fileptr *file)
{
   #iftemplatehasfunction< type, void Save(fileptr*) const >
      obj.Save( file );
   #else
      file->write( &obj, sizeof( obj ) );
   #endif
}
If not, is there another way around this type of situation? I use a templated function for resource management. But recently I realized that I need to allow some resource types to 'compare' themselves to other resources of the same type to see if the resources match completely regarding specifics for that type (IE, a skinmesh might need to compare morph targets). The only alternative would be to go back and force every object that can be loaded as a resource to implement a 'return true' version of this function. Thanks for any information.
sturmritter
sturmritter
you could use #ifndef and #define compiler directives to solve this problem I believe.

- Sturm
ToohrVyk
ToohrVyk
The closest I can get to this is to specialize the template for a class that has said Save method:

template <typename type> void SaveObject(const type &obj,fileptr *file){      file->write( &obj, sizeof( obj ) );}class Saveable { public: virtual void Save(fileptr* file) = 0; };template <> void SaveObject<Saveable>(const Saveable & obj,fileptr * file) {      obj.Save( file );}


This way, all classes inherited from Saveable will use the second one, while all other types will use the first one.
ToohrVyk
ToohrVyk
Quote:
Original post by sturmritter
you could use #ifndef and #define compiler directives to solve this problem I believe.


There are no #ifndef and #define compiler directives, sorry.

sturmritter
sturmritter
Meant Pre-processor directive. Sorry for confusion. I bag all directives into one lump.

Anyways, you could put your templates into a header file, and use the Pre-processor directives.

For example:

template
void SaveObject(const type &obj,fileptr *file)
{
#ifndef _Template_Specific_Function_
#define _Template_Specific_Function_
< type, void Save(fileptr*) const >
obj.Save( file );
#else
file->write( &obj, sizeof( obj ) );
#endif
}

Anyways, just a thought, I haven't tested it out.

- Sturm


ToohrVyk
ToohrVyk
Quote:
Original post by sturmritter
Meant Pre-processor directive. Sorry for confusion. I bag all directives into one lump.

Anyways, you could put your templates into a header file, and use the Pre-processor directives.


No problem. Say, how does your code work?
sturmritter
sturmritter
Well, I haven't actually run into Kest's problem myself, so it's more of a logic exercise for me.

the method above would seem rather cumbersome as you would have to change the #define line to fit whatever function you were looking for at compile time.

I'm not sure how to do it dynamically during run-time.

Perhaps using equal_to template? it's c-standard library template

[Source]Standard C++ Library Reference   equal_toSee Also<functional> MembersA binary predicate that tests whether a value of a specified type is equal to another value of that type.template<class Type>   struct equal_to : public binary_function<Type, Type, bool>    {      bool operator()(         const Type& _Left,          const Type& _Right      ) const;   };Parameters_Left The left operand of type Type in the equality to be tested. _Right The right operand of type Type in the equality to be tested. Return Valuetrue if _Left equals _Right; false if _Left does not equal _Right.RemarksThe objects of type Type must be equality comparable. This requires that the operator== defined on the set of objects satisfies the mathematical properties of an equivalence relation All the built-in numeric and pointer types satisfy this requirement.Example// functional_equal_to.cpp// compile with: /EHsc#include <vector>#include <functional>#include <algorithm>#include <iostream>using namespace std;int main( ){   vector <double> v1, v2, v3 ( 6 );   vector <double>::iterator Iter1, Iter2, Iter3;      int i;   for ( i = 0 ; i <= 5 ; i+=2 )   {      v1.push_back( 2.0 *i );      v1.push_back( 2.0 * i + 1.0 );   }   int j;   for ( j = 0 ; j <= 5 ; j+=2 )   {      v2.push_back( - 2.0 * j );      v2.push_back( 2.0 * j + 1.0 );   }   cout << "The vector v1 = ( " ;   for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ )      cout << *Iter1 << " ";   cout << ")" << endl;   cout << "The vector v2 = ( " ;   for ( Iter2 = v2.begin( ) ; Iter2 != v2.end( ) ; Iter2++ )      cout << *Iter2 << " ";   cout << ")" << endl;   // Testing for the element-wise equality between v1 & v2   transform ( v1.begin( ),  v1.end( ), v2.begin( ), v3.begin ( ),       equal_to<double>( ) );   cout << "The result of the element-wise equal_to comparison\n"      << " between v1 & v2 is: ( " ;   for ( Iter3 = v3.begin( ) ; Iter3 != v3.end( ) ; Iter3++ )      cout << *Iter3 << " ";   cout << ")" << endl;}OutputThe vector v1 = ( 0 1 4 5 8 9 )The vector v2 = ( 0 1 -4 5 -8 9 )The result of the element-wise equal_to comparison between v1 & v2 is: ( 1 1 0 1 0 1 )[/SOURCE]


Perhaps the operands of Type Type could be member functions rather than values?

Enigma
Enigma
You might be able to use SFINAE, depending on your compiler, i.e.:
#include <iostream>template < typename Type, void (Type:: *)() >struct HasMember{};template < typename Type >void DoSaveObject(Type const & object, HasMember< Type, &Type::Save > const *){	std::cout << "call save member function\n";}template < typename Type >void DoSaveObject(Type const & object, ...){	std::cout << "call alternative save function\n";}template < typename Type >void SaveObject(Type const & object){	DoSaveObject< Type >(object, 0);}struct HasSave{	void Save(){}};struct DoesntHaveSave{};int main(){	SaveObject(HasSave());	SaveObject(DoesntHaveSave());	SaveObject(int());}

Appears to work on VC++ 8.0. Fails on Borland 5.6.4 and GCC 3.3.1, but from what I've read it should work on GCC 3.4.x and presumably GCC 4.x too.

Σnigma

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.