需要一些模板编程帮助
我正在尝试扩展我的模板编程技能,但我遇到了一个我没有找到正确解决方案的问题。 这是一个个人培训练习,只是为了做一些更高级的模板。
目标是:编写一个模板,根据格式 sring 的类型将任何整数类型(使用 sprintf 或 swprintf)转换为 string 或 wstring。 不需要进行错误检查(目前为止)。
问题是当格式指定为 (const char*) NULL
或 (const wchar_t*) NULL
时,
我需要提供一个默认的 LITERAL 值作为 " %i"
或 L"%i"
为此,我需要确定格式变量的字符类型。 我现在正在使用一个函数,使用 SFINAE。 不过,我想为此使用一个变量,但我认为 SFINAY 不适用于变量(或者我错了)。
到目前为止,这是我的(工作)代码:
////////////////////////////////////////////////////////////////////////////////
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;
}
////////////////////////////////////////////////////////////////////////////////
我可以以类似的方式执行此操作还是工作版本是最好的方法? 或者如何做到这一点>
我不需要使用字符串流的建议(这不是这个问题的目的)。
使用 MSVS 2010(抱歉,没有提升)。
谢谢。
I am trying to expand my template programming skills and I am facing a problem to which I don't see the right solution for.
This is a personal training execise only to do some more advanced templating.
This the goal : write a template to convert any integer type (using sprintf or swprintf) to either string or wstring depending on the type of the format sring.
There is no need for error-checking (for now anuway).
The problem is when an format is specified as (const char*) NULL
or (const wchar_t*) NULL
I need to supply a default LITERAL value as either "%i"
or L"%i"
an for that I need to determine the char-type of the format-variable.
I am using a functions for that now ,using SFINAE.
However I would like to use a variable for that ,but I don't think SFINAY works on varaiables (or am i wrong).
Here is my (working) code so far:
////////////////////////////////////////////////////////////////////////////////
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;
}
////////////////////////////////////////////////////////////////////////////////
this this what i would like to do (obviously it's not workin)
////////////////////////////////////////////////////////////////////////////////
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;
}
////////////////////////////////////////////////////////////////////////////////
Can I do this in a simillar way or is the working version the best way ?
Or how to do this >
I don't need suggestion to use stringstreams (that's not what this question is about).
Using MSVS 2010 (and sorry ,no boost).
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
坦率地说,这是我能想到的唯一解决方案:
它并不漂亮,但它有效。
Frankly, this is the only solution I can think of:
It's not pretty, but it works.
您在第二个代码块中使用
enable_if
会变成硬错误,因为您没有在模板签名中使用它。您可能需要诸如boost::mpl::if_
之类的东西来计算变量dft
的类型;我相信您可以从窄字符串转换为宽字符串,以使您的格式在这两种情况下都能工作。Your uses of
enable_if
in your second code block turn into hard errors because you are not using it in the signature of a template. You might need something likeboost::mpl::if_
to compute the type of the variabledft
; I believe you can just cast from a narrow string to a wide one to get your format to work in both cases.IMO,你在这里尝试做的事情是相当无望的。 “%i”转换仅适用于整数,不适用于(例如)浮点类型,因此您的代码仅在
I
为int
1。对于任何其他类型,用户必须传递一个(正确的)格式字符串以使代码具有定义的行为。目前,我将忽略这个问题,并假设用户在I
不是int
时传递(正确的)格式字符串。虽然您将来可能想扩展到其他一些东西,但现在对于格式字符串的类型实际上只有两种可能:
char *
或wchar_t *
。既然如此,处理事情的正确方法似乎是简单的重载(或者专业化,如果你坚持的话):现在,你本质上正在做一个“切换类型”,这几乎总是可以避免的(并且通常最好避免)在 C++ 中。您在编译时而不是运行时执行此操作(或无论如何尝试)的小细节并没有真正改变这一点。
1好吧,您可能会说,如果
I
是unsigned int
并且值为在可以表示为int
的范围内,但这大约是您可以期望的最好结果(即使这是非常值得怀疑的)。IMO, what you're trying to do here is a pretty hopeless endeavor. A "%i" conversion will only work with integers, not (for example) floating point types, so your code only works if
I
isint
1. For any other type, the user must pass a (correct) format string for the code to have defined behavior. For the moment, I'll ignore this issue, and just assume the user passes a (correct) format string ifI
isn'tint
.While you might want to expand to a few other things sometime in the future, for now you really only have two possibilities for the type of the format string:
char *
orwchar_t *
. That being the case, it seems like the right way to handle things is a simple overload (or specialization, if you insist):Right now, you're doing essentially a "switch on type", something that's almost always avoidable (and generally best avoided) in C++. The minor detail that you're doing it (or trying to anyway) at compile-time instead of run-time doesn't really change that.
1Well, you might be able to argue that it should work if
I
isunsigned int
and the value is within the range that can be represented as anint
, but that's about the best you can hope for (and even that's highly questionable).