开发者

Need some help with template-programming

开发者 https://www.devze.com 2023-02-06 07:12 出处:网络
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.

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开发者_Python百科::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.


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. 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.


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).

0

精彩评论

暂无评论...
验证码 换一张
取 消