Jump to content
  • Advertisement
Sign in to follow this  
Shipwright

Variable argument number template functions

This topic is 4495 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to create a template function that takes a variable number of arguments with very little success. I understand that template classes must explicitly pass the template arguments, while template functions can deduce their arguments. I can write a one-size-fits-all template class member function, but explicitly writing out the argument list seems unnecessary, although it is a nice sanity check. Right now I have to write 10 different versions of the template function to support up to 10 arguments. Here's my feeble first attempt:


#define STATIC_ASSERT(exp) extern char CompileTimeAssert[ (exp) ? 1 : -1 ]

class NoType {
public:
	NoType() {}
	static NoType none;
};

template< typename T, int N >
class verify_arg {
public:
	static bool EVAL( lua_State *L ) {

		STATIC_ASSERT(0);
		// #pragma message(" Template did not find specialization for T" )
		// #error Template did not find specialization for T 
		return false;

	}	
};

template< int N >
class verify_arg< NoType, N > {
public:
	static bool EVAL( lua_State *L ) {
		// std::cout << "NoType " << " at " << N << std::endl;
		return true;
	}	
};

template< int N >
class verify_arg< float, N > {
public:
	static bool EVAL( lua_State *L ) {
		return lua_isnumber(L, N);
	}	
};

template< int N >
class verify_arg< int, N > {
public:
	static bool EVAL( lua_State *L ) {
		return lua_isinteger(L, N);
	}	
};

template< int N >
class verify_arg< std::string, N > {
public:
	static bool EVAL( lua_State *L ) {
		return lua_isstring(L, N);
	}	
};


template< int N, typename T >
class template_verify_arg {
public:
	static bool EVAL( lua_State *L ) {
		const bool thisArgument = verify_arg( 1.0f, L, N );
		return thisArgument && template_verify_arg< N-1, T >::EVAL(L);
	}	
};



template< typename T >
class template_verify_arg< 0, T > {
public:
	static bool EVAL( lua_State *L ) {
		return true;
	}	
};



template < typename A0, typename A1=NoType, typename A2=NoType, typename A3=NoType, typename A4=NoType, typename A5=NoType, typename A6=NoType, typename A7=NoType, typename A8=NoType, typename A9=NoType >
class template_verify_arguments {
public:
	static bool EVAL( lua_State *L ) {
		return 
			verify_arg< A0, 0 >::EVAL(L)
			&& verify_arg< A1, 1 >::EVAL(L)
			&& verify_arg< A2, 2 >::EVAL(L)
			&& verify_arg< A3, 3 >::EVAL(L)
			&& verify_arg< A4, 4 >::EVAL(L)
			&& verify_arg< A5, 5 >::EVAL(L)
			&& verify_arg< A6, 6 >::EVAL(L)
			&& verify_arg< A7, 7 >::EVAL(L)
			&& verify_arg< A8, 8 >::EVAL(L)
			&& verify_arg< A9, 9 >::EVAL(L);

	}	
};

inline bool verify_no_arguments( lua_State *L ) {
	return ( 0 == lua_gettop(L) );
}

template< typename T, int N >
class get_arg {
public:
	static bool EVAL( lua_State *L ) {

		STATIC_ASSERT(0);
		// #pragma message(" Template did not find specialization for T" )
		// #error Template did not find specialization for T 
		return false;

	}	
};

template< int N >
class get_arg< NoType, N > {
public:
	static bool EVAL( lua_State *L, NoType & ) {
		// std::cout << "NoType " << " at " << N << std::endl;
		return true;
	}	
};

template< int N >
class get_arg< double, N > {
public:
	static bool EVAL( lua_State *L, double &outValue ) {
		if( lua_isnumber(L, N) ) {
			// TODO: check to see if the double returned is within the single precision float range?
			outValue = lua_tonumber(L, N);
			return true;
		}
		return false;
	}	
};

template< int N >
class get_arg< float, N > {
public:
	static bool EVAL( lua_State *L, float &outValue ) {
		if( lua_isnumber(L, N) ) {
			// TODO: check to see if the double returned is within the single precision float range?
			outValue = static_cast< float >( lua_tonumber(L, N) );
			return true;
		}
		return false;
	}	
};

template< int N >
class get_arg< int, N > {
public:
	static bool EVAL( lua_State *L, int &outValue ) {
		if( lua_isnumber(L, N) ) {
			outValue = lua_tointeger(L, N);
			return true;
		}
		return false;
	}	
};

template< int N >
class get_arg< unsigned int, N > {
public:
	static bool EVAL( lua_State *L, unsigned int &outValue ) {
		if( lua_isnumber(L, N) ) {
			// lua_tointeger returns a 64 bit integer on the x86 platform, so this is safe
			//
			outValue = static_cast< unsigned int >( lua_tointeger(L, N) );
			return true;
		}
		return false;
	}	
};

template< int N >
class get_arg< std::string, N > {
public:
	static bool EVAL( lua_State *L, std::string &outValue ) {
		if( lua_isstring(L, N) ) {
			outValue = lua_tostring(L, N);
			return true;
		}
		return false;
	}	
};



template < typename A0=NoType, typename A1=NoType, typename A2=NoType, typename A3=NoType, typename A4=NoType, typename A5=NoType, typename A6=NoType, typename A7=NoType, typename A8=NoType, typename A9=NoType >
// template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9 >
class template_get_arguments {
public:
	static bool EVAL( lua_State *L, A0 &a0=NoType::none, A1 &a1=NoType::none, A2 &a2=NoType::none, A3 &a3=NoType::none, A4 &a4=NoType::none, A5 &a5=NoType::none, A6 &a6=NoType::none, A7 &a7=NoType::none, A8 &a8=NoType::none, A9 &a9=NoType::none ) {
		return 
			   get_arg< A0, 1 >::EVAL(L, a0)
			&& get_arg< A1, 2 >::EVAL(L, a1)
			&& get_arg< A2, 3 >::EVAL(L, a2)
			&& get_arg< A3, 4 >::EVAL(L, a3)
			&& get_arg< A4, 5 >::EVAL(L, a4)
			&& get_arg< A5, 6 >::EVAL(L, a5)
			&& get_arg< A6, 7 >::EVAL(L, a6)
			&& get_arg< A7, 8 >::EVAL(L, a7)
			&& get_arg< A8, 9 >::EVAL(L, a8)
			&& get_arg< A9, 10 >::EVAL(L, a9);
	}	
};
//// nest templates
//template < typename A0=NoType >
//class template_get_arguments< template_get_arguments< A1 > > {
//public:	
//	static bool EVAL( lua_State *L, A0 &a0=NoType::none, A1 &a1=NoType::none) {
//		return 
//			get_arg< A0, 0 >::EVAL(L, a0) && template_get_arguments< A1, 1 >::EVAL(L, a1) ;
//			
//	}	
//};

//template< typename T >
//class push_arg {
//public:
//	static void EVAL( lua_State *L ) {
//		STATIC_ASSERT(0);
//		// #pragma message(" Template did not find specialization for T" )
//		// #error Template did not find specialization for T 
//	}	
//};

//template< typename T >
//class push_arg< const T * > {
//public:
//	static void EVAL( lua_State *L, T arg ) {
//		STATIC_ASSERT(0);
//		lua_pushlightuserdata( L, arg );
//	}	
//};


#pragma warning( disable : 4100 ) // ignore unreferenced formal parameter warning
inline int push_arg( lua_State *L, NoType &arg=NoType::none ) {
	
	return 0;
	
}	
#pragma warning( default : 4100 )

template< typename T >
inline int push_arg( lua_State *L, T *arg ) {
	lua_pushlightuserdata( L, arg );
	return 1;
}	

template< typename T >
inline int push_arg( lua_State *L, T arg ) {
	STATIC_ASSERT(0);
}	


template< typename T >
inline int push_arg( lua_State *L, const T *arg ) {
	STATIC_ASSERT(0); // don't want to allow the pushing of pointers to constant data
}	


template <>
inline int push_arg( lua_State *L, float arg ) {
	lua_pushnumber( L, arg );
	return 1;
}	





template < typename A0=NoType, typename A1=NoType, typename A2=NoType, typename A3=NoType, typename A4=NoType, typename A5=NoType, typename A6=NoType, typename A7=NoType, typename A8=NoType, typename A9=NoType >
class template_push_arguments {
public:
	static int EVAL( lua_State *L, A0 &a0=NoType::none, A1 &a1=NoType::none, A2 &a2=NoType::none, A3 &a3=NoType::none, A4 &a4=NoType::none, A5 &a5=NoType::none, A6 &a6=NoType::none, A7 &a7=NoType::none, A8 &a8=NoType::none, A9 &a9=NoType::none ) {
		return push_arg( L, a0 )
			+  push_arg( L, a1 )
			+  push_arg( L, a2 )
			+  push_arg( L, a3 )
			+  push_arg( L, a4 )
			+  push_arg( L, a5 )
			+  push_arg( L, a6 )
			+  push_arg( L, a7 )
			+  push_arg( L, a8 )
			+  push_arg( L, a9 );
	}	
};

template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9 >
inline template_push_arguments< A0, A1, A2, A3, A4, A5, A6, A7, A8, A9 > 
make_push_args( A0=NoType, A1=NoType, A2=NoType, A3=NoType, A4=NoType, A5=NoType, A6=NoType, A7=NoType, A8=NoType, A9=NoType )
{
	return template_push_arguments< A0, A1, A2, A3, A4, A5, A6, A7, A8, A9 >();
}

template < typename A0 >
int lua_push_args( lua_State *L, A0 a0 )
{
	return template_push_arguments< A0, NoType, NoType, NoType, NoType, NoType, NoType, NoType, NoType >::EVAL( L, a0 );
}

template < typename A0, typename A1 >
int lua_push_args( lua_State *L, A0 a0, A1 a1 )
{
	return template_push_arguments< A0, A1, NoType, NoType, NoType, NoType, NoType, NoType, NoType >::EVAL( L, a0, a1 );
}

template < typename A0, typename A1, typename A2 >
int lua_push_args( lua_State *L, A0 a0, A1 a1, A2 a2 )
{
	return template_push_arguments< A0, A1, A2, NoType, NoType, NoType, NoType, NoType, NoType >::EVAL( L, a0, a1, a2 );
}



Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!