[英]How can I iterate over variadic template parameters in c++?
我正在嘗試使用可變參數模板(真的是第一次)來替換字符串 function。
本質上,我想制作一個 function(我們稱之為替換),它采用一個鍵值,該鍵值用於根據替換 function 中提供的附加參數搜索和修改模板字符串。模板字符串具有使用字符串“%s”。
我的問題是,我不確定如何遍歷可變模板參數...這是一些示例代碼。
const std::string FindOriginal(std::string Key)
{
if(Key == "Toon")
{
return "This is example %s in my program for Mr. %s.";
}
return "";
}
std::string Replace(std::string OriginalKey) {
return "";
}
template<typename First, typename ... Strings>
std::string Replace(std::string OriginalKey, First arg, const Strings&... rest)
{
const std::string from = "%s";
std::string the_string = FindOriginal(OriginalKey);
int i = 0;
size_t start_pos = the_string.find(from);
while(start_pos != std::string::npos)
{
// Ideally here I can somehow get the parameter at index i...
the_string.replace(start_pos, from.length(), rest[i]);
start_pos = the_string.find(from, start_pos);
i++;
}
Replace(rest...);
return the_string;
}
int main()
{
std::cout << Replace("Toon", "5", "Jimmy") << std::endl;
}
如果您有權訪問 C++17 或更高版本,您的邏輯最好用折疊表達式表示,它可以將 function 應用於包中每個參數的字符串(一元右折疊):
template<class T>
const std::string& ReplaceOne(std::string& originalString, const T& replacement)
{
static constexpr auto sentinel = "%s";
size_t start_pos = originalString.find(sentinel);
if(start_pos != std::string::npos)
originalString.replace(start_pos, 2, replacement);
return originalString;
}
template<class...Ts>
void Replace(std::string& originalString, const Ts&... rest)
{
(ReplaceOne(originalString, rest) , ...);
}
像這樣調用:
std::string original = "This is example %s in my program for Mr. %s.";
const std::string expected = "This is example 5 in my program for Mr. Jimmy.";
Replace(original, "5", "Jimmy");
assert(original == expected);
本質上,我們正在對我們的字符串調用ReplaceOne
以將"%s"
的單個實例替換為下一個可變參數。 如果沒有找到"%s"
,我們只返回不變的字符串。
我們使用一元右折疊,以便我們從左到右處理參數,因為順序很重要。
這種方法(實際上是您答案中的方法)的缺點是您正在為每個可變參數調用std::string::find
,這可能會搜索整個字符串。 在最壞的情況下,甚至在您的字符串中都沒有"%s"
的實例,因此,您在整個字符串中搜索每個替換項。 這是低效的; O(N * M)
其中N
是字符串的長度, M
是參數包中 arguments 的數量。
如果我們從find
的最后一個結果開始重復調用find
,我們可以將時間復雜度降低到O(N)
。 我現在將其作為練習留給您。
(另一種方法是將替換字符串存儲在一個臨時容器中,並像Stack Danny在這個答案中建議的那樣循環遍歷字符串(現已刪除)
你可以:
rest
)進行遞歸調用。arg
以及遞歸調用返回的任何內容。 我已將所有這些邏輯放入另一個 function ReplaceImpl
中,並讓Replace
進行早期檢查(例如,找到原始密鑰並在未找到原始密鑰時返回)。
##include <iostream>
#include <string>
const std::string FindOriginal(std::string Key) {
if (Key == "Toon") {
return "This is example %s in my program for Mr. %s.";
}
return {};
}
std::string ReplaceImpl(std::string str) {
return str;
}
template <typename First, typename... Strings>
std::string ReplaceImpl(std::string str, First arg, const Strings&... rest) {
if (auto pos{ str.find("%s") }; pos != std::string::npos) {
return
str.substr(0, pos) +
arg +
ReplaceImpl(str.substr(pos + 2), rest...);
}
return str;
}
template <typename First, typename... Strings>
std::string Replace(std::string OriginalKey, First arg, const Strings&... rest) {
if (auto the_string{ FindOriginal(OriginalKey) }; not the_string.empty()) {
return ReplaceImpl(the_string, arg, rest...);
}
return {};
}
int main() {
std::cout << Replace("Toon", "5", "Jimmy") << "\n";
}
// Outputs: This is example 5 in my program for Mr. Jimmy.
感謝某人關於通過遞歸調用工作的可變參數模板的評論,我設法更改了解決方案以獲得所需的結果。 基本上,我們將參數提供給調用可變參數模板 function (ReplaceValue) 的模板化 function (GetModifiedString)。
#include <iostream>
#include <string>
const std::string FindOriginal(const std::string& Key)
{
if(Key == "Toon")
{
return "This is example %s in my program for Mr. %s.";
}
return "";
}
void ReplaceValue(std::string& OriginalString)
{
(void)OriginalString;
}
template<typename First, typename ... Strings>
void ReplaceValue(std::string& OriginalString, First arg, const Strings&... rest)
{
const std::string from = "%s";
size_t start_pos = OriginalString.find(from);
if(start_pos != std::string::npos)
{
OriginalString.replace(start_pos, from.length(), arg);
}
ReplaceValue(OriginalString, rest...);
}
template<typename First, typename ... Strings>
std::string GetModifiedString(const std::string& OriginalKey, First arg, const Strings&... rest)
{
std::string modified_string = FindOriginal(OriginalKey);
ReplaceValue(modified_string, arg, rest...);
return modified_string;
}
int main()
{
std::cout << GetModifiedString("Toon", "5", "Jimmyy") << std::endl;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.