具有无限参数但具有相同(固定)类型的 C++ 函数

2024-01-08

我想要一个具有无限数量参数的函数,但我还想确保这些都是同一类型的指针。像这样的事情:

void myFunc(float value, MyClass* ....)
{
    // take all pointers of type MyClass and call function `f` like this: a->(value);
    // store pointer in a vector like: vector.push_back(a);
}

我可以用 C++ 实现这个吗?


void myFunc(float value, std::initializer_list<MyClass*> il){
  for(auto* p:il)
    p->f(value);
}

不会发生堆/空闲存储分配。

Use is myFunc(3.14, {ptr1,ptr2,ptr3});

如果你真的讨厌{}您可以使用不受限制的模板转发到上述内容。在转发时将进行类型检查。 SFINAE 可用于提前进行类型检查。

template<class...MyClasses>
void myFunc2( float value, MyClasses*... ps) {
  myFunc( value, {ps...} );
}

(可能会更改名称)

或者,可以完成基于 SFINAE 的完整解决方案,直接调用p->f,有点像用火箭筒处理垃圾。当然,垃圾会消失,但这仍然是一个坏主意。

初始值设定项列表旨在有效捆绑相同类型的参数。

现在,有一个关于您的好问题MyClass*请求是...你为什么关心?如果传入的参数兼容->f(3.14f),为什么不直接打电话->f(3.14f)?这就是为什么实际问题比抽象问题更适合提出:问题的最佳解决方案因实际问题而异。

火箭筒解决方案如下所示。

首先,一个小型模板元编程库:

// Better name for the type:
template<bool b>
using bool_t = std::integral_constant<bool, b>;
// bundle of types:
template<class...>struct types{using type=types;};

// takes a test, and a types<?...> of things to test against it:
template<template<class...>class Z, class args>
struct test_lists:std::true_type{};
template<template<class...>class Z, class...Ts, class...Us>
struct test_lists<Z,types<types<Ts...>,Us...>>:bool_t<
  Z<Ts...>{} && test_lists<Z, types<Us...>>{}
>{};

// takes 0 or more types<?...> and concatenates them:
template<class...types>
struct concat_types;
template<class...types>
using concat_types_t=typename concat_types<types...>::type;
template<>
struct concat_types<>:types<>{};
template<class...Ts>
struct concat_types<types<Ts...>>:types<Ts...>{};
template<class...T0s,class...T1s, class...more>
struct concat_types<types<T0s...>,types<T1s...>,more...>:
  concat_types_t< types<T0s...,T1s...>, more... >
{};

// takes a template Z and and arg, and produces a template
// equal to Z<Arg, ?...>:
template<template<class...>class Z, class Arg>
struct bind_1st {
    template<class...Ts>
    using apply=Z<Arg,Ts...>;
};

// takes a template Z and a types<?...> and produces
// types< Z<?>... >:
template<template<class...>class Z, class types>
struct map;
template<template<class...>class Z, class types>
using map_t=typename map<Z,types>::type;
template<template<class...>class Z, class...Ts>
struct map<Z,types<Ts...>>:types<Z<Ts>...>{};

// builds a cross product of zero or more types<?...>:
template<class...types0>
struct cross_types;
template<class...types>
using cross_types_t=typename cross_types<types...>::type;

// valid degenerate cases:
template<class...Ts>
struct cross_types<types<>,Ts...>:types<>{};
template<>
struct cross_types<>:types<types<>>{};

// meat of cross_types:
template<class T0, class...T0s, class...Us>
struct cross_types<types<T0,T0s...>, Us...>:
  concat_types_t<
    map_t< bind_1st< concat_types_t, types<T0> >::template apply, cross_types_t<Us...> >,
    cross_types_t< types<T0s...>, Us... >
  >
{};

// takes a test Z, and a sequence of types<?...> args
// tests the cross product of the contents of the args:
template<template<class...>class Z, class...Args>
struct test_cross : test_lists<Z, cross_types_t<Args...>> {};

这一点之上的所有内容都是通用元编程代码。您可以更直接地完成下一部分,但是上面的通用元编程代码可以用于其他类似的问题,并且它确实使后面的内容“更清晰”。

// a toy MyClass type to test against:
struct MyClass {
    void f(float x){
        std::cout << x << '\n';
    }
};

// Simple SFINAE test that the types passed in are exactly
// pointers to MyClass:
template<class...Ts>
std::enable_if_t<
  test_cross<std::is_same, types<MyClass>, types<Ts...>>{}
>
myFunc( float x, Ts*... p ) {
  using discard=int[];
  (void)discard{0,((
    p->f(x)
  ),void(),0)...};
}

注意std::is_base_of可能是一个更好的选择is_same.

核心在这里:

  test_cross<std::is_same, types<MyClass>, types<Ts...>>{}

这评估std::is_same<A,B>对于每对<MyClass, Ts>.

一个更简单的方法是使用一个模板,该模板需要大量bool...并做了一个&&在他们身上,连同std::is_same<MyClass, Ts>{}...。但我喜欢编写元编程库,并且简洁地进行 n 路交叉产品测试是一个更有趣的问题。

活生生的例子 http://coliru.stacked-crooked.com/a/4f227a57aa9325f9

基于的叉积python 中的这个堆栈溢出答案 https://stackoverflow.com/a/15102118/1774667

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有无限参数但具有相同(固定)类型的 C++ 函数 的相关文章

随机推荐