2012-01-25 13 views
2

我只是瞎搞與模板,當我試圖做到這一點:如何在使用std :: strings和c-style字符串時使用模板?

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::stringT將無法​​正常工作。因爲一個字符串不能被轉換爲char*,但是這個函數的編碼方式可以讓我同時傳遞一個c風格的char*數組和C++ std::string作爲參數,並將它們轉換爲LPCSTR

+0

什麼是'reinterpret_cast'的目的在這段代碼中,除了召喚煩惱? –

+0

請注意''MessageBox'需要**'LPCTSTR' **,這是一個寬字符串或一個窄字符串,取決於許多因素。我的猜測是,如果你想要通用和安全,你必須以某種方式複製字符串。你應該決定一個內部表示(也許UTF-8,所以你總是使用'char *'或'std :: string'),並在'MessageBox'調用位置轉換爲正確的Windows類型。請注意,Windows可能會要求您使用'wcout',而在Linux上,您應該始終使用'cout'。 –

+0

您可以通過測試'#ifdef _UNICODE'來測試'LPCTSTR'是否由寬字符組成。 Windows上的Unicode意味着(時下)UTF-16。 –

回答

5

您可以使用函數重載:

void print_error(char const* msg); 
void print_error(std::string const& msg); 
... 
+2

void print_error(std :: string const&msg){print_error(msg.c_str()); } – Totonga

+0

或甚至:'static inline void print_error(std :: string const&msg){print_error(msg.c_str()); }'優化它 –

3

這會工作:

#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 */ 
} 
+0

不,這不會(但幾乎)。根據平臺的不同,「MessageBox」的參數可能是寬字符串。 –

+0

@AlexandreC,好點。 – hmjd

2

有幾種方法來實現這一目標。其一是模板函數與函數重載組合:

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

另一種方式是部分專業類模板(函數模板不能是部分專業)來處理標籤模板參數告訴它該值的標準: :字符串:

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

要由hmjd提供的解決方案稍微闡述這個解決方案應該與任何字符串輸入工作,還整數等。它也應該與windows上激活的unicode一起工作。

#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 */ 
} 
+0

確實如此,但是在傳遞一個普通char *時性能上會降低性能,這會導致不必要的字符串複製至少一次,並且通常在字串流的開銷並不總是需要的時候。這是一個很好的通用函數,但我認爲它應該專用於char *和string –

1

,您可以啓用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; 
} 
相關問題