我正在尝试扩展我的模板编程技能,我正面临一个问题,我没有看到正确的解决方案。 这是个人训练,只是为了做一些更高级的模板。
这个目标:编写一个模板,将任何整数类型(使用sprintf或swprintf)转换为字符串或wstring,具体取决于格式的类型。 不需要进行错误检查(现在已经开始了)。
问题在于格式指定为(const char*) NULL
或(const wchar_t*) NULL
我需要提供默认的LITERAL值"%i"
或L"%i"
为此,我需要确定格式变量的char类型。
我现在正在使用SFINAE的功能。
但是我想使用一个变量,但我不认为SFINAY在varaiables上工作(或者我错了)。
到目前为止,这是我的(工作)代码:
////////////////////////////////////////////////////////////////////////////////
template < typename T ,typename I >
inline
typename std::enable_if< std::is_same< T ,char >::value ,int >::type
str_printf ( T* szBuff ,int iLen ,const T* szFrmt ,I iNum )
{ return sprintf_s( szBuff ,iLen ,szFrmt ,iNum ); }
template < typename T ,typename I >
inline
typename std::enable_if< std::is_same< T ,wchar_t >::value ,int >::type
str_printf ( T* szBuff ,int iLen ,const T* szFrmt ,I iNum )
{ return swprintf_s( szBuff ,iLen ,szFrmt ,iNum ); }
////////////////////////////////////////////////////////////////////////////////
template < typename T >
inline
typename std::enable_if< std::is_same< T ,char >::value ,const char* >::type
Dflt_Frmt () { return "%i"; }
template < typename T >
inline
typename std::enable_if< std::is_same< T ,wchar_t >::value ,const wchar_t* >::type
Dflt_Frmt () { return L"%i"; }
////////////////////////////////////////////////////////////////////////////////
template < typename T ,typename I >
inline
std::basic_string< T ,std::char_traits < T > >
to_string ( I iNum ,const T* pszFrmt )
{
const int iLen (65);
T szBuff [iLen] = {0};
std::basic_string< T ,std::char_traits < T > > frmt ((pszFrmt && (*pszFrmt)) ? pszFrmt : Dflt_Frmt<T>() );
str_printf( szBuff ,iLen ,frmt.c_str() ,iNum );
return szBuff;
}
////////////////////////////////////////////////////////////////////////////////
这就是我想做的事情(显然它不起作用)
////////////////////////////////////////////////////////////////////////////////
template < typename T ,typename I >
inline
std::basic_string< T ,std::char_traits < T > >
to_string ( I iNum ,const T* pszFrmt )
{
const int iLen (65);
T szBuff [iLen] = {0};
// declare a Variable of const T* and initialie it with "%i" or L"%i"
typename std::enable_if< std::is_same< T ,char >::value ,const char* >::type dft("%i");
typename std::enable_if< std::is_same< T ,wchar_t >::value ,const wchar_t* >::type dft (L"%i");
// doesn't work (error : type is not a member of std::enable_if< ... > !
std::basic_string< T ,std::char_traits < T > > frmt ((pszFrmt && (*pszFrmt)) ? pszFrmt : dft );
str_printf( szBuff ,iLen ,frmt.c_str() ,iNum );
return szBuff;
}
////////////////////////////////////////////////////////////////////////////////
我可以用类似的方式做到这一点,还是最好的工作版本? 或者如何执行此操作&gt;
我不需要建议使用stringstreams(这不是这个问题的内容)。
使用MSVS 2010(抱歉,没有提升)。
谢谢。
答案 0 :(得分:2)
坦率地说,这是我能想到的唯一解决方案:
template <typename T> struct Dft { static const T* value; };
template <> const char* Dft<char>::value = "%i";
template <> const wchar_t* Dft<wchar_t>::value = L"%i";
template < typename T ,typename I >
inline
std::basic_string< T ,std::char_traits < T > >
to_string ( I iNum ,const T* pszFrmt )
{
const int iLen (65);
T szBuff [iLen] = {0};
std::basic_string< T ,std::char_traits < T > > frmt ((pszFrmt && (*pszFrmt)) ? pszFrmt : Dft<T>::value );
str_printf( szBuff ,iLen ,frmt.c_str() ,iNum );
return szBuff;
};
它不漂亮,但它有效。
答案 1 :(得分:1)
您在第二个代码块中使用enable_if
会变成硬错误,因为您没有在模板的签名中使用它。您可能需要boost::mpl::if_
之类的内容来计算变量dft
的类型;我相信你可以从一个窄的字符串转换成一个宽的字符串,以使你的格式在两种情况下都能正常工作。
答案 2 :(得分:0)
I
为int
1 时,您的代码才有效。对于任何其他类型,用户必须传递(正确的)格式字符串,以使代码具有已定义的行为。目前,我将忽略此问题,并假设用户在I
不是int
时传递(正确的)格式字符串。
虽然您可能希望将来某个时间扩展到其他一些内容,但现在您只有两种可能的格式字符串类型:char *
或wchar_t *
。在这种情况下,处理事情的正确方法似乎是一个简单的重载(或专业化,如果你坚持):
template <class T>
std::string to_string(T val, char *fmt = "%i") {
// for the moment using `sprintf`, simply because every knows it -- not really
// advising its use in production code.
char buffer[256];
sprintf(buffer, fmt, val);
return std::string(buffer);
}
template <class T>
std::wstring to_string(T val, wchar_t *fmt = L"%i") {
wchar_t buffer[256];
wsprintf(buffer, fmt, val);
return std::wstring(buffer);
}
现在,你正在做一个“开启类型”,这在C ++中几乎总是可以避免(通常最好避免)。在编译时而不是运行时,你正在做(或者试图)的小细节并没有真正改变它。
1 好吧,如果I
为unsigned int
并且值在范围内,可能能够证明它应该有效可以表示为int
,但这是你所希望的最好的(甚至是非常值得怀疑的)。