[英]function parameter pack for member variable pointer
我正在嘗試通過嵌套成員指針訪問結構體中的變量:
#include <iostream>
typedef struct {
int a;
int b;
} bar;
typedef struct {
int c;
bar d;
} baz;
template <typename obj, class C1, class C2, typename T1, typename T2>
T2 test1(const obj& obj_, T1 C1::* field1_, T2 C2::* field2_)
{
return (obj_.*field1_).*field2_;
}
int main()
{
baz myObj;
test1(myObj, &baz::d, &bar::b);
}
如何將功能測試轉換為可變參數,以便可以在結構的變量“深度”處訪問變量? 我嘗試按照此處的功能參數列表部分中的第二個示例進行操作,但似乎無法理解它:
template <typename obj, class ...C, typename... T>
void test2(const obj& obj_, T C...::* field_)
{
// ??
// and what about the function return parameter?
}
int main()
{
baz myObj;
test2(obj,&baz::d,&bar::b);
test2(obj,&baz::c);
}
這樣, test2()
的定義就無法編譯。 可以使用任何(最新)C ++版本(盡管與MSVC一起使用)。 出於測試目的,這是有關coliru的完整程序 。
感謝Silvio的回答 ,我得以解決。 利用C ++ 17,它可以變得更短:
template <typename T, typename S, typename... Ss>
auto inline test2(const T& obj, S field1, Ss... fields)
{
if constexpr (!sizeof...(fields))
return obj.*field1;
else
return test2(obj.*field1, fields...);
}
可能有一種更清潔的方法來執行此操作,但是您當然可以采用C ++模板非常喜歡的“扔在牆上,看看有什么東西”的方法。
template <typename T>
auto test2(const T& obj) -> T {
return obj;
}
template <typename T, typename S, typename... Ss>
auto test2(const T& obj, S field1, Ss... fields)
-> decltype(test2(obj.*field1, fields...)) {
return test2(obj.*field1, fields...);
}
基本情況非常簡單。 如果我們不傳遞任何字段,則只返回原始對象本身。 遞歸的情況就是這樣:我們遞歸。 返回類型聲明為...返回值的聲明類型。 參數類型只是變量。 它們將根據需要完全實例化。 如果您傳遞沒有意義的參數或不鍵入check,則會收到一些非常丑陋的錯誤消息。
這需要c ++ 17支持折疊表達式。
namespace utils {
template<class T>struct tag_t{ using type=T; };
template<class...Ts>
using last = typename std::tuple_element_t< sizeof...(Ts)-1, std::tuple<tag_t<Ts>...> >::type;
template<class Lhs, class F>
struct fold_invoker_t;
template<class Lhs, class F>
fold_invoker_t<Lhs, F> fold_invoker(Lhs&&lhs, F&& f);
template<class Lhs, class F>
struct fold_invoker_t {
Lhs lhs;
F f;
template<class Rhs>
auto operator*( Rhs&& rhs )&& {
return fold_invoker(std::forward<F>(f)(std::forward<Lhs>(lhs), std::forward<Rhs>(rhs)), static_cast<F>(f));
}
};
template<class Lhs, class F>
fold_invoker_t<Lhs, F> fold_invoker(Lhs&&lhs, F&& f){ return {std::forward<Lhs>(lhs), std::forward<F>(f)}; }
}
然后我們寫:
template <typename Obj, class ...C, typename... T>
utils::last<Obj, T...> const& test2(const Obj& obj, T C::*... field)
{
auto get_member=[](auto&& elem, auto&& memptr)->decltype(auto){ return elem.*memptr; };
return (utils::fold_invoker( obj, get_member ) * ... * field).lhs;
}
並且全部都在那一行上擴展。
現場例子 。
不知道這是否可以在MSVC的C ++ 17支持下工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.