![](/img/trans.png)
[英]What is the easiest way to make template function code depending on the parameter type
[英]Make template function select type by function parameter
我有一些課程,比如
class A {
public:
void OnStageOne() {}
void OnStageTwo() {}
void OnStageThree() {}
};
class B {
public:
void OnStageOne() {}
void OnStageTwo() {}
void OnStageThree() {}
};
class C {
public:
void OnStageOne() {}
void OnStageTwo() {}
void OnStageThree() {}
};
我有一些向量來存儲它們:
std::vector<A> va;
std::vector<B> vb;
std::vector<C> vc;
現在我需要一些這樣的操作:對向量的所有元素調用OnStageXXX
,所以我寫了一個模板 function,如下所示:
template <typename T, void(T::*F)()>
void ForAll(std::vector<T> vector) {
for (auto& item : vector) {
(item.*F)();
}
}
它工作正常,除了我必須使用這樣的語法:
ForAll<A, &A::OnStageOne>(va);
由於可以為參數va
推導出第一個模板參數,有什么辦法可以使代碼更清晰? 喜歡ForAll<OnStageOne>(va);
?
或者,如果這是一個 A/B 問題,我可以通過任何方式編寫ForAll<OnStageXXX>(va);
對向量的每個元素調用OnStageXXX
?
PS我嘗試使用std::for_each
,但這會使語法更長。 我在這里尋求更短的語法來做到這一點,如果有的話。
在c++17 中:
template <auto F, typename T>
void ForAll(std::vector<T>& vector) {
for (auto& item : vector) {
(item.*F)();
}
}
用法:
ForAll<&A::OnStageOne>(va);
在c++20中:
constexpr auto OnStageOne = [] (auto& t) -> decltype(t.OnStageOne()) {
return t.OnStageOne();
};
constexpr auto OnStageTwo = [] (auto& t) -> decltype(t.OnStageTwo()) {
return t.OnStageTwo();
};
constexpr auto OnStageThree = [] (auto& t) -> decltype(t.OnStageThree()) {
return t.OnStageThree();
};
template <auto F, typename T>
requires requires (T t) { F(t); }
void ForAll(std::vector<T>& vector) {
for (auto& item : vector) {
F(item);
}
}
用法:
ForAll<OnStageOne>(va);
在c++11 / c++14 中(之前沒有基於范圍的 for 循環):
struct OnStageOne {
template <typename T>
void operator()(T& t) const { t.OnStageOne(); }
};
struct OnStageTwo {
template <typename T>
void operator()(T& t) const { t.OnStageTwo(); }
};
struct OnStageThree {
template <typename T>
void operator()(T& t) const { t.OnStageThree(); }
};
template <typename F, typename T>
void ForAll(std::vector<T>& vector) {
for (auto& item : vector) {
F{}(item);
}
}
用法:
ForAll<OnStageOne>(va);
這個答案從“XY 問題”的角度來解決這個問題:
或者,如果這是一個 A/B 問題,我可以通過任何方式編寫 ForAll(va); 之類的東西。 對向量的每個元素調用 OnStageXXX?
看來您的意圖是通過(未直接強制執行) OnStageXXX
編號接口的成員函數,為類A
、 B
和C
實現 static 多態性。 而不是解決“如何通過指向成員函數的指針(靜態)多態調用”的問題,您可能想查看如何實現類的“靜態接口”。
作為第一步,您可以將它們實現為在某個標簽上參數化的成員 function 模板,例如enum class
StageTag
,而不是為OnStageXXX
函數使用單獨的非模板成員函數。 這將允許您使用標記而不是指向成員 function 的指針來調用forAll(...)
function 來選擇要調用的成員 ZC1C425268E68385D1AB5074C17A94F14 特化。 例如:
#include <iostream>
#include <vector>
enum class StageTag { kOne, kTwo, kThree };
class A {
public:
template <StageTag> void OnStage() const = delete;
};
template <> void A::OnStage<StageTag::kOne>() const {
std::cout << "A OnStage kOne\n";
}
template <> void A::OnStage<StageTag::kTwo>() const {
std::cout << "A OnStage kTwo\n";
}
template <> void A::OnStage<StageTag::kThree>() const {
std::cout << "A OnStage kThree\n";
}
class B {
public:
template <StageTag> void OnStage() const = delete;
};
template <> void B::OnStage<StageTag::kOne>() const {
std::cout << "B OnStage kOne\n";
}
template <> void B::OnStage<StageTag::kTwo>() const {
std::cout << "B OnStage kTwo\n";
}
template <> void B::OnStage<StageTag::kThree>() const {
std::cout << "B OnStage kThree\n";
}
template <StageTag kTag, typename T> void ForAll(const std::vector<T> &vector) {
for (auto &item : vector) {
item.template OnStage<kTag>();
}
}
int main() {
const std::vector<A> va(3);
const std::vector<B> vb(2);
ForAll<StageTag::kThree>(va);
// A OnStage kThree
// A OnStage kThree
// A OnStage kThree
ForAll<StageTag::kOne>(vb);
// B OnStage kOne
// B OnStage kOne
return 0;
}
或者,您可以使用標簽調度來調度適當的非模板成員 function,而不是使用StageTag
的特化:
#include <iostream>
#include <vector>
enum class StageTag { kOne, kTwo, kThree };
class A {
private:
template <StageTag> struct ATag {};
public:
template <StageTag kTag> void OnStage() const { OnStage(ATag<kTag>{}); }
private:
void OnStage(ATag<StageTag::kOne>) const { std::cout << "A OnStage kOne\n"; }
void OnStage(ATag<StageTag::kTwo>) const { std::cout << "A OnStage kTwo\n"; }
void OnStage(ATag<StageTag::kThree>) const {
std::cout << "A OnStage kThree\n";
}
};
class B {
private:
template <StageTag> struct BTag {};
public:
template <StageTag kTag> void OnStage() const { OnStage(BTag<kTag>{}); }
private:
void OnStage(BTag<StageTag::kOne>) const { std::cout << "B OnStage kOne\n"; }
void OnStage(BTag<StageTag::kTwo>) const { std::cout << "B OnStage kTwo\n"; }
void OnStage(BTag<StageTag::kThree>) const {
std::cout << "B OnStage kThree\n";
}
};
template <StageTag kTag, typename T> void ForAll(const std::vector<T> &vector) {
for (auto &item : vector) {
item.template OnStage<kTag>();
}
}
int main() {
const std::vector<A> va(3);
const std::vector<B> vb(2);
ForAll<StageTag::kThree>(va);
// A OnStage kThree
// A OnStage kThree
// A OnStage kThree
ForAll<StageTag::kOne>(vb);
// B OnStage kOne
// B OnStage kOne
return 0;
}
您可能還想查看 Curiously Recurring Template Pattern來強制執行您的 static 接口。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.