需要一些模板编程帮助

发布于 2024-10-14 13:04:04 字数 3179 浏览 1 评论 0原文

我正在尝试扩展我的模板编程技能,但我遇到了一个我没有找到正确解决方案的问题。 这是一个个人培训练习,只是为了做一些更高级的模板。

目标是:编写一个模板,根据格式 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

南街九尾狐 2024-10-21 13:04:04

坦率地说,这是我能想到的唯一解决方案:

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;
};

它并不漂亮,但它有效。

Frankly, this is the only solution I can think of:

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;
};

It's not pretty, but it works.

萌︼了一个春 2024-10-21 13:04:04

您在第二个代码块中使用 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 like boost::mpl::if_ to compute the type of the variable dft; I believe you can just cast from a narrow string to a wide one to get your format to work in both cases.

梦在深巷 2024-10-21 13:04:04

IMO,你在这里尝试做的事情是相当无望的。 “%i”转换仅适用于整数,不适用于(例如)浮点类型,因此您的代码仅在 Iint1。对于任何其他类型,用户必须传递一个(正确的)格式字符串以使代码具有定义的行为。目前,我将忽略这个问题,并假设用户在 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好吧,您可能会说,如果Iunsigned 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 is int1. 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 if I isn't int.

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 * or wchar_t *. That being the case, it seems like the right way to handle things is a simple overload (or specialization, if you insist):

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);
}

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 is unsigned int and the value is within the range that can be represented as an int, but that's about the best you can hope for (and even that's highly questionable).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文