简体   繁体   English

在模板编程方面需要一些帮助

[英]Need some help with template-programming

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. 目的是:编写一个模板,根据格式字符串的类型,将任何整数类型(使用sprintf或swprintf)转换为字符串或wstring。 There is no need for error-checking (for now anuway). 无需进行错误检查(目前为anuway)。

The problem is when an format is specified as (const char*) NULL or (const wchar_t*) NULL 问题是当格式指定为(const char*) NULL(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. 我需要提供默认的LITERAL值作为"%i"L"%i" ,因为我需要确定格式变量的字符类型。 I am using a functions for that now ,using SFINAE. 我现在使用SFINAE为此使用函数。 However I would like to use a variable for that ,but I don't think SFINAY works on varaiables (or am i wrong). 但是我想为此使用一个变量,但是我不认为SFINAY适用于变量(或者我错了)。

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). 使用MSVS 2010(很抱歉,没有帮助)。

Thank you. 谢谢。

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. 它不漂亮,但是可以用。

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. 您在第二个代码块中使用的enable_if会变成硬错误,因为您没有在模板的签名中使用它。 You might need something like boost::mpl::if_ to compute the type of the variable dft ; 您可能需要boost::mpl::if_之类的boost::mpl::if_来计算变量dft的类型; I believe you can just cast from a narrow string to a wide one to get your format to work in both cases. 我相信您可以将一个狭窄的字符串转换为一个宽字符串,以使您的格式在两种情况下均能正常工作。

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 int 1 . “%i”转换仅适用于整数,而不适用于(例如)浮点类型,因此,您的代码仅在Iint 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 if I isn't int . 目前,我将忽略此问题,如果I不是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 * . 尽管将来可能需要扩展到其他内容,但到目前为止,对于格式字符串的类型,您实际上只有两种可能: char *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++. 现在,您实际上正在执行“打开类型”,这在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. 您在编译时而不是运行时执行(或尝试尝试)的次要细节并不会真正改变这一点。

1 Well, 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). 1好吧,您也许可以说,如果Iunsigned int且该值在可以表示为int的范围内,那么它应该可以工作,但这只是您所希望的最好(甚至是非常可疑的)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM