由於C++ 11,我們可使它可以接受的參數中的任何序列模板功能:C++參數包,受限於具有單一類型的實例?
template <typename... Ts>
void func(Ts &&... ts) {
step_one(std::forward<Ts>(ts)...);
step_two(std::forward<Ts>(ts)...);
}
但是,假如它真的纔有意義,叫我在功能的情況下,每個參數具有相同的類型 - 儘管如此,任何數量的參數都可以。
這樣做的最好方法是什麼,即是否有一種很好的方法來限制模板在這種情況下生成一個很好的錯誤消息,或理想情況下,當參數不匹配時消除func
參與重載解析?
我可以使它真正具體的,如果有幫助:
假設我有一些結構:
struct my_struct {
int foo;
double bar;
std::string baz;
};
現在,我希望能夠做的事情一樣,打印的成員用於調試目的的結構體,對結構體進行序列化和反序列化,按順序訪問結構體的成員等等。我有一些代碼可以幫助解決這個問題:
template <typename V>
void apply_visitor(V && v, my_struct & s) {
std::forward<V>(v)("foo", s.foo);
std::forward<V>(v)("bar", s.bar);
std::forward<V>(v)("baz", s.baz);
}
template <typename V>
void apply_visitor(V && v, const my_struct & s) {
std::forward<V>(v)("foo", s.foo);
std::forward<V>(v)("bar", s.bar);
std::forward<V>(v)("baz", s.baz);
}
template <typename V>
void apply_visitor(V && v, my_struct && s) {
std::forward<V>(v)("foo", std::move(s).foo);
std::forward<V>(v)("bar", std::move(s).bar);
std::forward<V>(v)("baz", std::move(s).baz);
}
(它看起來有點費力,產生這樣的代碼,但是我做了a small library前一段時間,以幫助這一點。)
所以,現在我想擴展它,以便它可以訪問的my_struct
兩個實例與此同時。那就是,如果我想實現平等或比較操作的話。在boost::variant
文件中,他們稱之爲「二元探視」,與「一元探視」形成對比。
也許,沒有人會希望做更多的二進制訪問。但是,假設我想要這樣做,一般n-ary
訪問。然後,它看起來像這樣我猜
template <typename V, typename ... Ss>
void apply_visitor(V && v, Ss && ... ss) {
std::forward<V>(v)("foo", (std::forward<Ss>(ss).foo)...);
std::forward<V>(v)("bar", (std::forward<Ss>(ss).bar)...);
std::forward<V>(v)("baz", (std::forward<Ss>(ss).baz)...);
}
但現在,它越來越多一點瘋狂的 - 如果有人經過一系列的甚至不是同一個結構類型的所有類型,代碼可以編譯仍並完成用戶完全意想不到的事情。
我想過做這樣的:
template <typename V, typename ... Ss>
void apply_visitor(V && v, Ss && ... ss) {
auto foo_ptr = &my_struct::foo;
std::forward<V>(v)("foo", (std::forward<Ss>(ss).*foo_ptr)...);
auto bar_ptr = &my_struct::bar;
std::forward<V>(v)("bar", (std::forward<Ss>(ss).*bar_ptr)...);
auto baz_ptr = &my_struct::baz;
std::forward<V>(v)("baz", (std::forward<Ss>(ss).*baz_ptr)...);
}
,至少如果他們不匹配的類型使用它會導致編譯錯誤。但是,它也發生得太晚了 - 這發生在模板類型解決後,並且在我認爲重載解決之後。
我曾考慮過使用SFINAE,而不是返回void,使用std::enable_if_t
並檢查參數包中每種類型的某種表達式std::is_same<std::remove_cv_t<std::remove_reference_t<...>>
。但是對於一個,SFINAE表達式相當複雜,對於兩個,它也有一個缺點 - 假設有人有派生類struct my_other_struct : my_struct { ... }
,並且他們希望將它與訪客機制一起使用,所以一些參數是my_struct
,有些是my_other_struct
。理想情況下,系統會將所有引用轉換爲my_struct
,並以這種方式應用訪問者,並且我使用成員指針foo_ptr
,bar_ptr
,baz_ptr
的上例給出的示例會在那裏做正確的事情,但是我不清楚如何寫像SFINAE這樣的約束 - 我將不得不嘗試找到我猜測的所有參數的共同基礎?
有沒有一種很好的方法來調和這些問題?
'std :: common_type'? – cpplearner
你希望它們都是特定的已知類型,還是隻是爲了相同,未知類型? – Quentin
@cpplearner:哦,那真是太好了,我不知道那個 –