簡體   English   中英

C++ 使用模板元編程生成 function

[英]C++ generate function with template metaprogramming

如何使用模板元編程生成 function。 我想要做的是有一堆基本上做同樣事情的函數:

Type1 fun1(int arg1, int arg2) {
  Type1 newType1 = {};
  newType1.arg1 = arg1;
  newType1.arg2 = arg2;

  return newType1;
}

Type2 fun2(int arg1, int arg2, int arg3, bool arg4) {
  Type2 newType2 = {};
  newType2.arg1 = arg1;
  newType2.arg2 = arg2;
  newType2.arg3 = arg3;
  newType2.arg4 = arg4;

  return newType2;
}

所以基本上我不想自己編寫所有這些函數,例如我想說我想要一個 function fun1 ,它需要兩個 int arguments 並使用模板將它們分配給一個新的 object 但是如何?

我的想法是有一個模板 function 接受一個類型(這里是 Type1 或 Type2)和指向這些類型的成員的指針,所以我唯一要做的就是給模板指向成員的指針,它會生成function 取對應類型的 arguments。

這是答案:

template<auto PMem>
struct member_type {};
template<class T, class M, M(T::*ptr)>
struct member_type<ptr> { using type=M; };
template<auto PMem>
using member_type_t=typename member_type<PMem>::type;

template<class T, auto...PMem>
T func( member_type_t<PMem>... args ) {
  T retval = {};
  ( ((retval.*PMem) = std::forward<member_type_t<PMem>>(args)), ... );
  return retval;
}

測試代碼:

struct Bob {
  int x,y;
};

int main() {
    Bob b = func<Bob, &Bob::x, &Bob::y>( 2, 3 );
    (void)b;
}

活生生的例子

您也可以在不匹配類型的情況下完善前進。 這樣做的缺點是不起作用:

struct A {
  int x, y;
};
struct B {
  A one, two;
};
B func<B, &B::one, &B::two>( {1,2}, {3,4} );

但它確實消除了上面的一些樣板,它可以消除每個成員字段的冗余移動。

為此,只需完全刪除member_type助手:

template<class T, auto...PMem, class...Args>
T func( Args&&... args ) {
  T retval = {};
  ( ((retval.*PMem) = std::forward<Args>(args)), ... );
  return retval;
}

之外執行此操作很痛苦。 您缺少auto參數和...擴展語句。 第二個使用一些樣板文件相對容易解決,但第一個使您想要的語法基本上不可能; 您可能會減少使用宏。

如果你不想要<>語法:

template<class T, auto...PMem>
constexpr auto make_func() {
  return +[]( member_type_t<PMem>... args )->T {
    T retval = {};
    ( ((retval.*PMem) = std::forward<member_type_t<PMem>>(args)), ... );
    return retval;
  };
}

struct Bob {
  int x,y;
};

constexpr auto* func = make_func<Bob, &Bob::x, &Bob::y>();    

活生生的例子

constexpr function 指針應該與 function 幾乎沒有區別,除非重載不可用。

在 MSVC 中,您可能必須像這樣消除 function 指針類型的歧義:

template<class T, auto...PMem>
using func_t = T(*)(member_type_t<PMem>...);

template<class T, auto...PMem>
constexpr func_t<T, PMem...> make_func() {
  return []( member_type_t<PMem>... args )->T {
    T retval = {};
    ( ((retval.*PMem) = std::forward<member_type_t<PMem>>(args)), ... );
    return retval;
  };
}

活生生的例子

有時MSVC 在具有多個不同調用約定選項的無狀態 lambda 上的一元運算符+存在問題。 以上避免了這個問題,但代價是一些樣板。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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