簡體   English   中英

成員變量指針的函數參數包

[英]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,則會收到一些非常丑陋的錯誤消息。

這需要支持折疊表達式。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM