Как использовать шаблоны при работе со строками std :: strings и c-style? - PullRequest
2 голосов
/ 25 января 2012

Я просто возился с шаблонами, когда пытался это сделать:

template<typename T> void print_error(T msg)
{
#ifdef PLATFORM_WIN32
    ::MessageBox(0, reinterpret_cast< LPCSTR >(msg), "Error", MB_ICONERROR|MB_OK);
#else
    cout << msg << endl;
#endif /* PLATFORM_WIN32 */
}

Конечно, это не сработает, если вы передадите std::string как T.Поскольку строка не может быть приведена к char*, но может ли эта функция быть закодирована таким образом, чтобы она позволяла передавать как массив char* в стиле c, так и c ++ std::string в качестве параметров,преобразовать их в LPCSTR?

Ответы [ 5 ]

5 голосов
/ 25 января 2012

Вы можете использовать функцию перегрузки:

void print_error(char const* msg);
void print_error(std::string const& msg);
...
3 голосов
/ 25 января 2012

Это будет работать:

#include <sstream>

template<typename T> void print_error(T msg)
{
    std::ostringstream s;
    s << msg;

#ifdef PLATFORM_WIN32
    ::MessageBox(0, s.str().c_str(), "Error", MB_ICONERROR|MB_OK);
#else
    cout << s.str() << endl;
#endif /* PLATFORM_WIN32 */
}
2 голосов
/ 25 января 2012

Есть несколько способов добиться этого.Одним из них является объединение шаблонных функций с перегрузкой функций:

template<typename T>
void print_error(T msg)
{
   ::MessageBox(0, reinterpret_cast< LPCSTR >(msg), "Error", MB_ICONERROR|MB_OK);
   cout << msg << endl;
}

void print_error(const std::string& msg)
{
   ::MessageBox(0, reinterpret_cast< LPCSTR >(msg.c_str()), "Error", MB_ICONERROR|MB_OK);
   cout << msg << endl;
}

int main()
{
string test = "test";
print_error(test);
print_error("test");
return 0;
}

Другой способ заключается в частичной специализации шаблона класса (шаблоны функций не могут быть частично специализированы) для обработки тегового аргумента шаблона, который сообщает ему, что значение являетсяstd :: string:

template <typename T>
class StringArgument{};

template <typename T>
struct ErrorPrinter
{
static void print_error(T msg)
{
   ::MessageBox(0, reinterpret_cast< LPCSTR >(msg), "Error", MB_ICONERROR|MB_OK);
}
};

template <typename T>
struct ErrorPrinter<StringArgument<T> >
{
static void print_error(T msg)
{
   ::MessageBox(0, reinterpret_cast< LPCSTR >(msg.c_str()), "Error", MB_ICONERROR|MB_OK);
}
};

int main()
{
string test = "test";   
ErrorPrinter<const char*>::print_error("sdfsdfsdf");
ErrorPrinter<StringArgument<string> >::print_error(test);

return 0;
}
1 голос
/ 26 января 2012

Вы можете включить print_error, если T - char *, иначе это будет ошибка времени компиляции, т.е. (вам нужно включить type_traits и c ++ 11):

template<typename T> 
typename std::enable_if< std::is_same<T, char*>::value, void>::type print_error(T msg)
{
    ::MessageBox(0, reinterpret_cast< LPCSTR >(msg), "Error", MB_ICONERROR|MB_OK);
    cout << msg << endl;
}
1 голос
/ 25 января 2012

Чтобы немного уточнить решение, предлагаемое hmjd, это решение должно работать с любым строковым вводом, а также целыми числами и тому подобным. Он также должен работать с юникодом, активированным в Windows.

#include <sstream>

template<typename T> void print_error(T msg)
{
#ifdef PLATFORM_WIN32
    std::basic_ostringstream< TCHAR > ss;
    ss << msg;
    ::MessageBox(0, ss.str().c_str(), "Error", MB_ICONERROR|MB_OK);
#else
    cout << msg << endl;
#endif /* PLATFORM_WIN32 */
}
...