C++ namespaceを使って既存のテンプレートをカスタマイズ

namespace をうまく使うと既存のテンプレートをきれいにカスタマイズすることができます

std::map と文字列の自然順比較

std::map のキーに std::string を使うとその要素はデフォルトでは辞書順に並びます
これを自然順に並ぶようにするにはどうすればいいでしょうか

std::map の要素の並び順はテンプレートの第三引数である less 関数によるので基本的にはここに文字列の自然順比較をする less を指定すればいいだけです
ただ、単純にそういったクラスを用意するだけでは std::map のテンプレート引数に毎回そのクラスを指定することになってしまって使うときにいちいち面倒ですね

template<class T> struct natural_order_less : public std::less<T> {};
template<> struct natural_order_less<std::string> : public std::binary_function<std::string,std::string,bool> {
	bool operator()( const std::string&	lhs, const std::string&	rhs ) const {
		return	( &lhs[0] == &rhs[0] ) ? false : ( strcmp_by_natural_order( &lhs[0], &rhs[0] ) < 0 );
	}
};
template<> struct natural_order_less<std::wstring> : public std::binary_function<std::wstring,std::wstring,bool> {
	bool operator()( const std::wstring&	lhs, const std::wstring&	rhs ) const {
		return	( &lhs[0] == &rhs[0] ) ? false : ( wcscmp_by_natural_order( &lhs[0], &rhs[0] ) < 0 );
	}
};
std::map<std::string,int,natural_order_less<std::string> >	aaa;
.
.
.
for( std::map<std::string,int,natural_order_less<std::string> >::iterator	p = aaa.begin(); p != aaa.end(); ++p ){
	...
}

こういうときには専用の namespace を作ると少し便利になりますよ
文字列の自然順比較専用の namespace を作りましょう

namespace natural_order {
template<class T> struct less : public std::less<T> {};
template<> struct less<std::string> : public std::binary_function<std::string,std::string,bool> {
	bool operator()( const std::string&	lhs, const std::string&	rhs ) const {
		return	( &lhs[0] == &rhs[0] ) ? false : ( strcmp_by_natural_order( &lhs[0], &rhs[0] ) < 0 );
	}
};
template<> struct less<std::wstring> : public std::binary_function<std::wstring,std::wstring,bool> {
	bool operator()( const std::wstring&	lhs, const std::wstring&	rhs ) const {
		return	( &lhs[0] == &rhs[0] ) ? false : ( wcscmp_by_natural_order( &lhs[0], &rhs[0] ) < 0 );
	}
};
template<class _key_type, class _value_type, class _less_type = less<_key_type>, class _allocator_type = std::allocator<std::pair<const _key_type, _value_type> > > struct map : public std::map<_key_type,_value_type,_less_type,_allocator_type> {};
}

こうして専用の namespace を作っておくと使うときも簡単でしかも自然順比較の map であることも一目瞭然になります

natural_order::map<std::string,int>  aaa;
.
.
.
for( natural_order::map<std::string,int>::iterator	p = aaa.begin(); p != aaa.end(); ++p ){
	...
}

簡単ですね

std::map のキー文字列の大文字小文字を無視

今度は std::map のキー文字列の大文字小文字を無視したいとしましょう

aaa["aaA"] = 1;
aaa["aaa"] = 2;
aaa["AAA"] = 3;

出力

aaA

このようなときはどうすればいいでしょうか

#include	<string>
#include	<map>

namespace case_insensitive {
template<class T> struct less : public std::less<T> {};
template<> struct less<std::string> : public std::binary_function<std::string,std::string,bool> {
	bool operator()( const std::string&	lhs, const std::string&	rhs ) const {
		return	( &lhs[0] == &rhs[0] ) ? false : ( stricmp( &lhs[0], &rhs[0] ) < 0 );
	}
};
template<> struct less<std::wstring> : public std::binary_function<std::wstring,std::wstring,bool> {
	bool operator()( const std::wstring&	lhs, const std::wstring&	rhs ) const {
		return	( &lhs[0] == &rhs[0] ) ? false : ( wcsicmp( &lhs[0], &rhs[0] ) < 0 );
	}
};
template<class _key_type, class _value_type, class _less_type = less<_key_type>, class _allocator_type = std::allocator<std::pair<const _key_type, _value_type> > > struct map : public std::map<_key_type,_value_type,_less_type,_allocator_type> {};
}
#include	<windows.h>

inline void	OutputDebugStringA( const std::string&	s ){
	OutputDebugStringA( &s[0] );
}

int	main(){
	case_insensitive::map<std::string,int>  aaa;
	aaa["aaa"] = 1;
	aaa["AAA"] = 2;
	aaa["aaA"] = 3;
	for( case_insensitive::map<std::string,int>::iterator	p = aaa.begin(); p != aaa.end(); ++p ){
		OutputDebugString( p->first );
		OutputDebugString( "\n" );
	}
	return	0;
}

出力

aaa

std::map のキー文字列を大文字に

今度は std::map のキー文字列を大文字にしたいとしましょう

bbb[L"BbB"] = 1;
bbb[L"bBB"] = 2;
bbb[L"BBb"] = 3;

出力

BBB

このようなときはどうすればいいでしょうか

#include	<string>

template<typename _plain_type, typename _signed_type = _plain_type,typename _unsigned_type = _plain_type> struct signed_unsigned {
	typedef _plain_type		plain_type;
	typedef _signed_type	signed_type;
	typedef _unsigned_type	unsigned_type;
};
template<> struct signed_unsigned<char> : public signed_unsigned<char,signed char,unsigned char> {};
template<> struct signed_unsigned<signed char> : public signed_unsigned<char,signed char,unsigned char> {};
template<> struct signed_unsigned<unsigned char> : public signed_unsigned<char,signed char,unsigned char> {};

template<class char_type> struct ctype {
	static char_type	toupper ( char_type	c ){ return	( char_type )::toupper ( signed_unsigned<char_type>::unsigned_type( c )); };
	static char_type	tolower ( char_type	c ){ return	( char_type )::tolower ( signed_unsigned<char_type>::unsigned_type( c )); };
};
template<> struct ctype<wchar_t> {
	static wchar_t	toupper ( wchar_t	wc ){ return	( wchar_t )::towupper ( wc ); };
	static wchar_t	tolower ( wchar_t	wc ){ return	( wchar_t )::towlower ( wc ); };
};

namespace upper_case {
template<class char_type> struct char_traits : public std::char_traits<char_type> {
	// 本当はこの3つだけでいいんだけど仮想関数じゃないから他のも全部オーバーライドするよ
	static void	assign( char_type& lhs, const char_type&	rhs ){
		lhs = ctype<char_type>::toupper ( rhs );
	}
	static bool	eq( const char_type&	lhs, const char_type&	rhs ){
		return ( ctype<char_type>::toupper ( lhs ) == ctype<char_type>::toupper ( rhs ));
	}
	static bool	lt( const char_type&	lhs, const char_type&	rhs ){
		return ( ctype<char_type>::toupper ( lhs ) < ctype<char_type>::toupper ( rhs ));
	}
	
	// 
	static int	compare( const char_type*	lhs, const char_type*	rhs, size_t	cch ){
		int	result = 0;
		while( cch > 0 ){
			if( !eq( *lhs, *rhs )){
				result = lt( *lhs, *rhs ) ? -1 : +1;
				break;
			}
			++lhs;
			++rhs;
			--cch;
		}
		return	result;
	}
	static size_t	length( const char_type*	s ){
		const char_type*	p = s;
		while( !eq( *p, char_type())){
			++p;
		}
		return	p - s;
	}
	static char_type*	copy( char_type*	d, const char_type*	s, size_t	cch ){
		return	copy( d, cch, s, cch );
	}
	static char_type*	copy( char_type*	d, size_t cch_d, const char_type*	s, size_t cch_s ){
		char_type*	p = d;
		while( cch_s > 0 ){
			assign( *p, *s );
			++p;
			++s;
			--cch_s;
		}
		return	d;
	}
	static const char_type*	find( const char_type*	p, size_t cch, const char_type&	ch ){
		const char_type* result = 0;
		while( cch > 0 ){
			if( eq( *p, ch )){
				result = p;
				break;
			}
			++p;
			--cch;
		}
		return	result;
	}
	static char_type*	move( char_type*	d, const char_type*	s, size_t cch ){
		return	move( d, cch, s, cch );
	}
	static char_type*	move( char_type*	d, size_t cch_d, const char_type*	s, size_t cch_s ){
		char_type*	p = d;
		if(( p > s )&&( p < s + cch_s )){
			p += cch_s;
			s += cch_s;
			while( cch_s > 0 ){
				assign( *--p, *--s );
				--cch_s;
			}
		}
		else{
			while( cch_s > 0 ){
				assign( *p, *s );
				++p;
				++s;
				--cch_s;
			}
		}
		return	d;
	}
	static char_type*	assign( char_type*	d, size_t cch, char_type ch ){
		char_type*	p = d;
		while( cch > 0 ){
			assign( *p, ch );
			++p;
			--cch;
		}
		return	d;
	}
	// これは大文字小文字に関係ないから基底クラスのでいいよ
	//static char_type	to_char_type( const int_type& _Meta );
	//static int_type	to_int_type( const char_type&	ch );
	//static bool	eq_int_type( const int_type& lhs, const int_type& rhs );
	//static int_type	eof();
	//static int_type	not_eof( const int_type& _Meta );
};
typedef std::basic_string<char,char_traits<char>,std::allocator<char> >	string;
typedef std::basic_string<wchar_t,char_traits<wchar_t>,std::allocator<wchar_t> >	wstring;
}
#include	<windows.h>
#include	<map>

inline void	OutputDebugStringA( const upper_case::string&	s ){
	OutputDebugStringA( &s[0] );
}
inline void	OutputDebugStringW( const upper_case::wstring&	s ){
	OutputDebugStringW( &s[0] );
}

int	main(){
	std::map<upper_case::string,int>  aaa;
	aaa["aaa"] = 1;
	aaa["AAA"] = 2;
	aaa["aaA"] = 3;
	for( std::map<upper_case::string,int>::iterator	p = aaa.begin(); p != aaa.end(); ++p ){
		OutputDebugString( p->first );
		OutputDebugString( "\n" );
	}
	std::map<upper_case::wstring,int>  bbb;
	bbb[L"BbB"] = 1;
	bbb[L"bBB"] = 2;
	bbb[L"BBb"] = 3;
	for( std::map<upper_case::wstring,int>::iterator	p = bbb.begin(); p != bbb.end(); ++p ){
		OutputDebugStringW( p->first );
		OutputDebugString( "\n" );
	}
	return	0;
}

出力

AAA
BBB

std::map のキー文字列を小文字に

今度は std::map のキー文字列を小文字にしたいとしましょう

bbb[L"BbB"] = 1;
bbb[L"bBB"] = 2;
bbb[L"BBb"] = 3;

出力

bbb

このようなときはどうすればいいでしょうか

もちろん大文字のときと同じように小文字用の char_traits<> を書くのですが、毎回 char_traits のメソッドをいくつも、しかも同じ内容のものを書くのもばかばかしいですよね
ここは char_traits<> の assign, eq, lt だけを書けばいいようにしてみましょう

struct char_traits_exception {
	static void	out_of_range(){
		__debugbrak();
	}
};
template<class char_type, class traits_class = std::char_traits<char_type>, class exception_class = char_traits_exception> struct char_traits : public traits_class {
	// この3つは派生クラスで定義させるよ
	//static void	assign( char_type& lhs, const char_type&	rhs );
	//static bool	eq( const char_type&	lhs, const char_type&	rhs );
	//static bool	lt( const char_type&	lhs, const char_type&	rhs );
	
	// コピー/比較に関するメソッドは traits_class に指定されたクラスの assign, eq, lt を使う
	static int	compare( const char_type*	lhs, const char_type*	rhs, size_t	cch ){
		int	result = 0;
		while( cch > 0 ){
			if( !traits_class::eq( *lhs, *rhs )){
				result = traits_class::lt( *lhs, *rhs ) ? -1 : +1;
				break;
			}
			++lhs;
			++rhs;
			--cch;
		}
		return	result;
	}
	static size_t	length( const char_type*	s ){
		const char_type*	p = s;
		while( !traits_class::eq( *p, char_type())){
			++p;
		}
		return	p - s;
	}
	static char_type*	copy( char_type*	d, const char_type*	s, size_t	cch ){
		return	copy( d, cch, s, cch );
	}
	static char_type*	copy( char_type*	d, size_t cch_d, const char_type*	s, size_t cch_s ){
		if( cch_d < cch_s ){
			out_of_range();
		}
		char_type*	p = d;
		while( cch_s > 0 ){
			traits_class::assign( *p, *s );
			++p;
			++s;
			--cch_s;
		}
		return	d;
	}
	static const char_type*	find( const char_type*	p, size_t cch, const char_type&	ch ){
		const char_type* result = 0;
		while( cch > 0 ){
			if( traits_class::eq( *p, ch )){
				result = p;
				break;
			}
			++p;
			--cch;
		}
		return	result;
	}
	static char_type*	move( char_type*	d, const char_type*	s, size_t cch ){
		return	move( d, cch, s, cch );
	}
	static char_type*	move( char_type*	d, size_t cch_d, const char_type*	s, size_t cch_s ){
		if( cch_d < cch_s ){
			out_of_range();
		}
		char_type*	p = d;
		if(( p > s )&&( p < s + cch_s )){
			p += cch_s;
			s += cch_s;
			while( cch_s > 0 ){
				traits_class::assign( *--p, *--s );
				--cch_s;
			}
		}
		else{
			while( cch_s > 0 ){
				traits_class::assign( *p, *s );
				++p;
				++s;
				--cch_s;
			}
		}
		return	d;
	}
	static char_type*	assign( char_type*	d, size_t cch, char_type ch ){
		char_type*	p = d;
		while( cch > 0 ){
			traits_class::assign( *p, ch );
			++p;
			--cch;
		}
		return	d;
	}
	// コピー/比較に関係ないメソッドは基底クラスのでいいよ
	//static char_type	to_char_type( const int_type& _Meta );
	//static int_type	to_int_type( const char_type&	ch );
	//static bool	eq_int_type( const int_type& lhs, const int_type& rhs );
	//static int_type	eof();
	//static int_type	not_eof( const int_type& _Meta );
};

そうすると小文字用の char_traits<> はこんなに簡単になります

namespace lower_case {
template<class char_type> struct char_traits : public ::char_traits<char_type,char_traits<char_type> > {
	static void	assign( char_type& lhs, const char_type&	rhs ){
		lhs = ctype<char_type>::tolower ( rhs );
	}
	static bool	eq( const char_type&	lhs, const char_type&	rhs ){
		return ( ctype<char_type>::tolower ( lhs ) == ctype<char_type>::tolower ( rhs ));
	}
	static bool	lt( const char_type&	lhs, const char_type&	rhs ){
		return ( ctype<char_type>::tolower ( lhs ) < ctype<char_type>::tolower ( rhs ));
	}
};
typedef std::basic_string<char,char_traits<char>,std::allocator<char> >	string;
typedef std::basic_string<wchar_t,char_traits<wchar_t>,std::allocator<wchar_t> >	wstring;
}
#include	<windows.h>
#include	<map>

inline void	OutputDebugStringA( const lower_case::string&	s ){
	OutputDebugStringA( &s[0] );
}
inline void	OutputDebugStringW( const lower_case::wstring&	s ){
	OutputDebugStringW( &s[0] );
}

int	main(){
	std::map<lower_case::string,int>  aaa;
	aaa["aaa"] = 1;
	aaa["AAA"] = 2;
	aaa["aaA"] = 3;
	for( std::map<lower_case::string,int>::iterator	p = aaa.begin(); p != aaa.end(); ++p ){
		OutputDebugString( p->first );
		OutputDebugString( "\n" );
	}
	std::map<lower_case::wstring,int>  bbb;
	bbb[L"BbB"] = 1;
	bbb[L"bBB"] = 2;
	bbb[L"BBb"] = 3;
	for( std::map<lower_case::wstring,int>::iterator	p = bbb.begin(); p != bbb.end(); ++p ){
		OutputDebugStringW( p->first );
		OutputDebugString( "\n" );
	}
	return	0;
}

出力

aaa
bbb

余談

ところで、テストコードのところにそれぞれの namespace の string 用にいくつも OutputDebugString を定義していたのにお気づきでしたでしょうか

inline void	OutputDebugStringA( const std::string&	s ){
	OutputDebugStringA( &s[0] );
}
inline void	OutputDebugStringW( const std::wstring&	s ){
	OutputDebugStringW( &s[0] );
}
inline void	OutputDebugStringA( const upper_case::string&	s ){
	OutputDebugStringA( &s[0] );
}
inline void	OutputDebugStringW( const upper_case::wstring&	s ){
	OutputDebugStringW( &s[0] );
}
inline void	OutputDebugStringA( const lower_case::string&	s ){
	OutputDebugStringA( &s[0] );
}
inline void	OutputDebugStringW( const lower_case::wstring&	s ){
	OutputDebugStringW( &s[0] );
}

このように同じものをいくつも書くのは無駄ですね
これは引数としてそれぞれの namespace にある string を受け取ろうとしているところから来る問題なので、共通の基底クラスである std::basic_string<> を受け取るようにすれば std::string でも upper_case::string でも lower_case::string でも使えるようになりますよ

template<class _char_type,class _traits_type,class _allocator_type> inline void	OutputDebugStringA( const std::basic_string<_char_type,_traits_type,_allocator_type>&	s ){
	OutputDebugStringA( &s[0] );
}
template<class _char_type,class _traits_type,class _allocator_type> inline void	OutputDebugStringW( const std::basic_string<_char_type,_traits_type,_allocator_type>&	s ){
	OutputDebugStringW( &s[0] );
}

同じコードがといえば、下記に自然順比較のコードの一例を載せておきますが、マルチバイトとワイドキャラクタでほとんど同じですね
本当はこういうときこそテンプレートですよ

// 自然順比較:文字列中の数字の並びを1つの数字として比較します
// 単純な辞書順の様に aaa1, aaa10, aaa2 などとはならず、aaa1, aaa2, aaa10 となります
int	strcmp_by_natural_order( const char*	s1, const char*	s2 ){
#if	( TEMPORARY_STRING_SIZE == 0 )
	size_t	cch1 = strlen( s1 );
	size_t	cch2 = strlen( s2 );
	size_t	cchTemp = cch1 + cch2;
	size_t	cbTemp = sizeof( char ) * ( cchTemp+1 );
	char*	temp1 = ( char* )malloc( cbTemp );
	char*	temp2 = ( char* )malloc( cbTemp );
#else // TEMPORARY_STRING_SIZE
	char	temp1[TEMPORARY_STRING_SIZE];
	char	temp2[TEMPORARY_STRING_SIZE];
#endif // TEMPORARY_STRING_SIZE
	int	result = 0;
	size_t	ns1 = 0;
	size_t	ns2 = 0;
	do{
		if( isdigit(( unsigned char )s1[ns1] ) && isdigit(( unsigned char )s2[ns2] )){
			// 文字列中の数字部分は数値として比較する
			char*	i1 = temp1;
			char*	i2 = temp2;
			size_t		ni1 = 0;
			size_t		ni2 = 0;
			// 整数部分の切り出し
			do{
				i1[ni1] = s1[ns1];
				++ni1;
				++ns1;
			}while( s1[ns1] && isdigit(( unsigned char )s1[ns1] ));
			do{
				i2[ni2] = s2[ns2];
				++ni2;
				++ns2;
			}while( s2[ns2] && isdigit(( unsigned char )s2[ns2] ));
			// 短い方の前に 0 を入れて桁を揃える
			if( ni1 < ni2 ){
				size_t	m = ni2 - ni1;
				for( size_t	i = 0; i < ni1; ++i ){
					i1[m+ni1-i-1] = i1[ni1-i-1];
				}
				{for( size_t	i = 0; i < m; ++i ){
					i1[i] = '0';
				}}
				ni1 += m;
			}
			else if( ni1 > ni2 ){
				size_t	m = ni1 - ni2;
				for( size_t	i = 0; i < ni2; ++i ){
					i2[m+ni2-i-1] = i2[ni2-i-1];
				}
				{for( size_t	i = 0; i < m; ++i ){
					i2[i] = '0';
				}}
				ni2 += m;
			}
			if(( s1[ns1] == '.' )||( s2[ns2] == '.' )){
				// 小数部分の切り出し
				if( s1[ns1] == '.' ){
					do{
						i1[ni1] = s1[ns1];
						++ni1;
						++ns1;
					}while( s1[ns1] && isdigit(( unsigned char )s1[ns1] ));
				}
				else{
					i1[ni1] = '.';
					++ni1;
				}
				if( s2[ns2] == '.' ){
					do{
						i2[ni2] = s2[ns2];
						++ni2;
						++ns2;
					}while( s2[ns2] && isdigit(( unsigned char )s2[ns2] ));
				}
				else{
					i2[ni2] = '.';
					++ni2;
				}
				// 短い方の後ろに 0 を入れて桁を揃える
				if( ni1 < ni2 ){
					size_t	m = ni2 - ni1;
					for( size_t	i = 0; i < m; ++i ){
						i1[ni1] = '0';
						++ni1;
					}
				}
				else if( ni1 > ni2 ){
					size_t	m = ni1 - ni2;
					for( size_t	i = 0; i < m; ++i ){
						i2[ni2] = '0';
						++ni2;
					}
				}
			}
			i1[ni1] = '\0';
			i2[ni2] = '\0';
			result = strncmp( &i1[0], &i2[0], ni1 );
		}
		else{
			// 数字以外の文字は普通に比較する
			result = ( int )( unsigned char )s1[ns1] - ( int )( unsigned char )s2[ns2];
			while( s1[ns1] && s2[ns2] && !result ){
				if( isdigit(( unsigned char )s1[ns1] ) || isdigit(( unsigned char )s2[ns2] )){
					break;
				}
				unsigned int	c1 = ( unsigned int )( unsigned char )s1[ns1];
				unsigned int	c2 = ( unsigned int )( unsigned char )s2[ns2];
				if( _ismbblead( c1 ) && _ismbblead( c2 )){
					c1 = ( c1 << 8 ) | ( unsigned int )( unsigned char )s1[ns1+1];
					c2 = ( c2 << 8 ) | ( unsigned int )( unsigned char )s2[ns2+1];
					ns2 += 2;
					ns1 += 2;
				}
				else if( _ismbblead( c1 )){
					c1 = ( c1 << 8 ) | ( unsigned int )( unsigned char )s1[ns1+1];
					++ns2;
					ns1 += 2;
				}
				else if( _ismbblead( c2 )){
					c2 = ( c2 << 8 ) | ( unsigned int )( unsigned char )s2[ns2+1];
					ns2 += 2;
					++ns1;
				}
				else{
					++ns2;
					++ns1;
				}
				result = ( int )( c1 - c2 );
			}
		}
	}while( s1[ns1] && s2[ns2] && !result );
	if(( s1[ns1] != s2[ns2] )&&( !s1[ns1] || !s2[ns2] )){
		unsigned int	c1 = ( unsigned int )( unsigned char )s1[ns1];
		unsigned int	c2 = ( unsigned int )( unsigned char )s2[ns2];
		if( _ismbblead( c1 )){
			c1 = ( c1 << 8 ) | ( unsigned int )( unsigned char )s1[ns1+1];
		}
		else if( _ismbblead( c2 )){
			c2 = ( c2 << 8 ) | ( unsigned int )( unsigned char )s2[ns2+1];
		}
		if( !result ){
			result = ( int )( c1 - c2 );
		}
	}
#if	( TEMPORARY_STRING_SIZE == 0 )
	free( temp2 );
	free( temp1 );
#endif // TEMPORARY_STRING_SIZE
	return	result;
}
int	wcscmp_by_natural_order( const wchar_t*	s1, const wchar_t*	s2 ){
#if	( TEMPORARY_STRING_SIZE == 0 )
	size_t	cch1 = wcslen( s1 );
	size_t	cch2 = wcslen( s2 );
	size_t	cchTemp = cch1 + cch2;
	size_t	cbTemp = sizeof( wchar_t ) * ( cchTemp+1 );
	wchar_t*	temp1 = ( wchar_t* )malloc( cbTemp );
	wchar_t*	temp2 = ( wchar_t* )malloc( cbTemp );
#else // TEMPORARY_STRING_SIZE
	wchar_t	temp1[TEMPORARY_STRING_SIZE];
	wchar_t	temp2[TEMPORARY_STRING_SIZE];
#endif // TEMPORARY_STRING_SIZE
	int	result = 0;
	size_t	ns1 = 0;
	size_t	ns2 = 0;
	do{
		if( iswdigit( s1[ns1] ) && iswdigit( s2[ns2] )){
			// 文字列中の数字部分は数値として比較する
			wchar_t*	i1 = temp1;
			wchar_t*	i2 = temp2;
			size_t		ni1 = 0;
			size_t	ni2 = 0;
			// 整数部分の切り出し
			do{
				i1[ni1] = s1[ns1];
				++ni1;
				++ns1;
			}while( s1[ns1] && iswdigit( s1[ns1] ));
			do{
				i2[ni2] = s2[ns2];
				++ni2;
				++ns2;
			}while( s2[ns2] && iswdigit( s2[ns2] ));
			// 短い方の前に 0 を入れて桁を揃える
			if( ni1 < ni2 ){
				size_t	m = ni2 - ni1;
				for( size_t	i = 0; i < ni1; ++i ){
					i1[m+ni1-i-1] = i1[ni1-i-1];
				}
				{for( size_t	i = 0; i < m; ++i ){
					i1[i] = L'0';
				}}
				ni1 += m;
			}
			else if( ni1 > ni2 ){
				size_t	m = ni1 - ni2;
				for( size_t	i = 0; i < ni2; ++i ){
					i2[m+ni2-i-1] = i2[ni2-i-1];
				}
				{for( size_t	i = 0; i < m; ++i ){
					i2[i] = L'0';
				}}
				ni2 += m;
			}
			if(( s1[ns1] == L'.' )||( s2[ns2] == L'.' )){
				// 小数部分の切り出し
				if( s1[ns1] == L'.' ){
					do{
						i1[ni1] = s1[ns1];
						++ni1;
						++ns1;
					}while( s1[ns1] && iswdigit( s1[ns1] ));
				}
				else{
					i1[ni1] = L'.';
					++ni1;
				}
				if( s2[ns2] == L'.' ){
					do{
						i2[ni2] = s2[ns2];
						++ni2;
						++ns2;
					}while( s2[ns2] && iswdigit( s2[ns2] ));
				}
				else{
					i2[ni2] = L'.';
					++ni2;
				}
				// 短い方の後ろに 0 を入れて桁を揃える
				if( ni1 < ni2 ){
					size_t	m = ni2 - ni1;
					for( size_t	i = 0; i < m; ++i ){
						i1[ni1] = L'0';
						++ni1;
					}
				}
				else if( ni1 > ni2 ){
					size_t	m = ni1 - ni2;
					for( size_t	i = 0; i < m; ++i ){
						i2[ni2] = L'0';
						++ni2;
					}
				}
			}
			i1[ni1] = L'\0';
			i2[ni2] = L'\0';
			result = wcsncmp( &i1[0], &i2[0], ni1 );
		}
		else{
			// 数字以外の文字は普通に比較する
			result = s1[ns1] - s2[ns2];
			while( s1[ns1] && s2[ns2] && !result && !iswdigit( s1[ns1] ) && !iswdigit( s2[ns2] )){
				result = s1[ns1] - s2[ns2];
				++ns2;
				++ns1;
			}
		}
	}while( s1[ns1] && s2[ns2] && !result );
	if(( s1[ns1] != s2[ns2] )&&( !s1[ns1] || !s2[ns2] )){
		if( !result ){
			result = ( int )(( unsigned int )s1[ns1] - ( unsigned int )s2[ns2] );
		}
	}
#if	( TEMPORARY_STRING_SIZE == 0 )
	free( temp2 );
	free( temp1 );
#endif // TEMPORARY_STRING_SIZE
	return	result;
}

それから malloc じゃなくて _alloca/_malloca とかにした方がいいですね