我正在嘗試學習 C Win32。我為游戲環境構建了一個計時器類。典型的游戲計時器,效果很好。我有這個功能,我想用它來顯示當前的游戲時間。
std::wstring Time::DisplayGameTime()
{
std::wstring Label = L"Current Time: ";
std::wstring daysText = L" " std::to_wstring(Days()); //Returns int
std::wstring monthsText = L", " std::to_wstring(Months()); //Returns int
std::wstring yearsText = L", " std::to_wstring(Years()); // Returns int
std::wstring hoursText = L" " std::to_wstring(Hours()); // Returns int
std::wstring minutesText = L" : " std::to_wstring(Minutes()); // Returns int
std::wstring message = Label daysText monthsText yearsText hoursText minutesText;
return message;
}
這也很有效,除了分鐘整數只列印一個數字,直到它達到 10。我想像在正常時鐘中找到的那樣填充前導零。因為我使用的是 std::to_wstring,所以我不能像在 swprintf_s 緩沖區中那樣使用格式說明符。我試圖弄清楚如何為此使用 wstringstream,但我嘗試過的都沒有奏效。
目標是稍后使用此函式轉換為 LPCWSTR,以便 DrawText 顯示到視窗。
uj5u.com熱心網友回復:
您可以使用傳統的命令式“蠻力”方法來解決這個問題:
int DaysVal = Days();
std::wstring W = (DaysVal < 10 ? L"0" : L"") std::to_wstring(DaysVal);
或..std::stringstream與std::setwand std::setfill(from <iomanip>) 一起使用。
std::wstringstream WS;
WS << std::setw(2) << std::setfill(L'0') << Days();
std::wstring W = WS.str();
PS:來自<iomanip>同樣作業std::cout和其他流的功能,所以 std::(w)stringstream對于 I/O 來說是不必要的!
編輯:如果有人正在尋找解決方案snprintf():
char CB[128];
std::snprintf(CB, sizeof(CB), "%.*i", NumDigits, Num);
使用精度(%.*i)優于使用寬度(%*i),因為第二個對字符總數而不是位數進行操作!
編輯(2):為了面向未來,我還包括一個解決方案,使用std::format():
我已經很久沒有玩{fmt}了,所以我不知道如何達到與printf(). 現在,它應該足夠了(但期望負數少一位):
std::wstring W = fmt::format(L"{: 0{}}", Num, NumDigits);
uj5u.com熱心網友回復:
將輸出寫入std::wstringstream物件與寫入std::wcout流非常相似;您連續撥打<<接線員電話;然后,完成后,您可以使用成員函式wstring獲取底層物件的副本。.str()
std::setw您可以使用和函式單獨控制每個欄位的寬度和填充字符std::setfill- 如果需要,您可以在要調整其輸出的每個欄位之前呼叫這些。
在您的情況下,您可以對除最后一個欄位之外的所有欄位使用默認格式,您可以將寬度設定為 2 并將填充字符設定為L'0':
#include <sstream>
#include <string>
#include <iomanip>
std::wstring Time::DisplayGameTime()
{
std::wstringstream message;
message
<< L"Current Time: "
// D,M,Y,H using default format ...
<< L" " << Days()
<< L", " << Months()
<< L", " << Years()
<< L" " << Hours()
// Add Minute using zero-padded, fixed width of 2 ...
<< L" : " << std::setw(2) << std::setfill(L'0') << Minutes();
return message.str();
}
uj5u.com熱心網友回復:
正如您發現的那樣,to_wstring不允許您提供格式選項。如果您想繼續使用to_wstring,則必須自己應用格式。有很多選擇,所以我隨機選擇一個:
- 總是在前面加上
"0" - 然后回傳最右邊的 2 位數字
像這樣的東西:
auto const minutesText = []() {
// Always prepend a "0"
auto const minute { L"0" std::to_wstring(Minutes()) };
// Return the right-most 2 digits
return minute.substr(minute.length() - 2);
}();
如果你可以使用 C 20,事情就會容易得多,而且通常也會快得多。C 20 引入了一個格式化庫,它結合了簡潔的格式化描述語言(類似于 Python 的)和 C 的 I/O 流的型別安全性。
它使以下實作成為可能:
#include <format>
std::wstring Time::DisplayGameTime()
{
return std::format(L"Current Time: {}, {}, {} {} : {:02}",
Days(), Months(), Years(),
Hours(), Minutes());
}
std::format類似于printf函式系列,采用格式化字串,加上零個或多個要插值的引數。格式化字串描述了最終輸出以及引數的放置位置和格式化方式。
前四個占位符不包含任何格式規范,并產生類似于to_wstring會產生的結果。最后的占位符{:02}對欄位寬度 ( 2) 和填充字符 ( 0) 進行編碼,以便在輸出沒有產生足夠的字符時使用。它可能被拼寫{:0>2}為指定右對齊的文本,但這是默認整數值,所以我省略了它。
使用 C 20 格式化庫需要 C 20 編譯器(實作它)。Visual Studio 2019 和 Visual Studio 2022 可以。任何一個都需要設定/std:c -latest編譯器選項。此時,C 20 格式化庫并沒有出現在/std:c 20編譯器選項下。C 語言標準也可以從 IDE 中設定。
獎勵材料: 為什么 std::format 這樣做?- Charlie Barto - CppCon 2021:看看 Microsoft 的實施,除其他外,解釋了為什么std::format比 I/O 流快幾個數量級。這不是介紹性材料。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/428296.html
