利用模板元编程的C++生成函数。

问题描述 投票:1回答:2

如何利用模板元编程生成一个函数。我想做的是有一堆函数,基本上都是做同样的事情。

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;
}

所以基本上我不想自己写这些函数 我想比如说我想要一个函数 fun1 取两个int参数,并使用模板将它们赋值给一个Type1的新对象,但是如何做呢?

我的想法是有一个模板函数,它接受一个类型(这里是Type1或Type2)和这些类型的指针到成员,所以我唯一要做的就是给模板提供指针到成员,它就会生成接受相应类型参数的函数。

c++ templates metaprogramming
2个回答
4
投票

这是一个 答案

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函数指针的处理应该与函数几乎没有区别,除了重载不可用。

在MSVC中,你可能需要像这样来区分函数指针类型。

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在单利运算符方面存在问题 + 在无状态的lambdas上有多个不同的调用约定optoins。 上面的方法避免了这个问题,但代价是增加了一些模板。

© www.soinside.com 2019 - 2024. All rights reserved.