具有多个相同类型参数的模板函数

wja*_*jan 9 c++ templates variadic c++14

我正在尝试创建一个函数,该函数可以采用相同类型的多个参数,并作为模板传入。参数的数量在编译时是已知的:

struct Foo
{
    int a, b, c;
};

template <uint32_t argsCount, typename T>
void fun(T ...args) // max number of args == argsCount
{
    // ...
    // std::array<T, argsCount>{ args... };
}

int main()
{
    fun<3, Foo>( { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } );

    // Dont want to do:
    // fun( Foo{}, Foo{}, Foo{} );
    // nor:
    // fun<Foo, Foo, Foo>( ... );

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我必须考虑这些限制:

  • 没有堆内存分配
  • 没有 va_args

是否可以在 C++14 中做类似的事情(最好是 C++14,但好奇新版本中的解决方案是什么)?

编辑:清理了最初的马虎伪代码。

Evg*_*Evg 9

在调用站点上使用稍微不同的语法,您可以通过引用数组来实现:

template<typename T, std::size_t N>
void fun(const T(& args)[N]) {
    auto args_as_stdarray = std::to_array(args);
}

fun<Foo>({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
Run Code Online (Sandbox Code Playgroud)


Art*_*yer 8

如果将函数改为函子,则可以在函子类型的主体中引入参数包。

首先创建一个helper来转<N, T>-> std::tuple<T, T, T, ..., T>(N次):

template<std::size_t N, typename T>
struct repeat {
private:
    // enable_if<true, T> == type_identity<T>
    template<std::size_t... I>
    static std::enable_if<true, std::tuple<std::enable_if_t<I==I, T>...>>
    get(std::index_sequence<I...>);
public:
    using type = typename decltype(get(std::make_index_sequence<N>{}))::type;
};
Run Code Online (Sandbox Code Playgroud)

然后让你的函子接受一个std::tuple<Args...>,其中Args将是一个带有T N时间的参数包:

template<typename T, typename Args>
struct fun_t;

template<typename T, typename... Args>
struct fun_t<T, std::tuple<Args...>> {
    static constexpr std::size_t argsCount = sizeof...(Args);

    void operator()(Args... args) const {
        // ...
        // std::array<T, argsCount>{ args... };
    }
};

template<std::uint32_t argCount, typename T>
constexpr fun_t<T, typename repeat<argCount, T>::type> fun;


int main() {
    fun<3, Foo>({ 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 });
}
Run Code Online (Sandbox Code Playgroud)


Yak*_*ont 7

template <class T0, class...Ts,
  std::enable_if_t< std::is_same_v<T0, Ts> && ..., bool > =true
>
void fun(T0 arg0, Ts ...args)
{
  constexpr auto argsCount = sizeof...(args)+1;
  std::array<T0, argsCount>{ arg0, args... };
}
Run Code Online (Sandbox Code Playgroud)

这是中完成,它只需要更多的输入,而且我很懒(主要替换折叠表达式)。

这要求调用站点有Foos,这是您不希望的。

template<std::size_t I, class T>
struct helper { using type = T; };
template<std::size_t I, class T>
using X = typename helper<I,T>::type;

template<class T, std::size_t...Is>
void fun(std::index_sequence<Is...>, X<Is, T>... ts) {
  std::array<T, sizeof...(Is)> args(ts...);
}
Run Code Online (Sandbox Code Playgroud)

使用:

fun<Foo>( std::make_index_sequence<7>, /* 7 Foo objects */ );
Run Code Online (Sandbox Code Playgroud)

我们还可以这样做:

fun<Foo, 7>()( /* 7 Foo objects */ );
Run Code Online (Sandbox Code Playgroud)

略有变化:

template<class T, std::size_t N> 
auto fun() {
  auto seq = std::make_index_sequence<N>{};
  return []<std::size_t...Is>(std::index_sequence<Is...>) {
    return [](X<Is, Foo>... ts) {
      std::array<Foo, sizeof...(Is)> args{ts...};
    };
  }( seq );
}
Run Code Online (Sandbox Code Playgroud)

这是,但您可以通过编写参数包解包器向后移植到

这里的技巧是foo<Foo,7>()返回一个知道它7 Foo准确获取对象的函数对象。

活生生的例子

中,我们可以:

template<class T, class Pack>
struct fun_impl;
template<class T, std::size_t...Is>
struct fun_impl<T, std::index_sequence<Is...>> {
  void operator()(X<Is, T>... ts)const {
    std::array<T, sizeof...(Is)> args{ts...};
  }
};
template<class T, std::size_t N>
auto fun() {
  return fun_impl<T, std::make_index_sequence<N>>{};
}
Run Code Online (Sandbox Code Playgroud)

现场示例(基于下面@Jarod42 的版本)。

  • 通过使用函子类,C++14 替代方案并不那么长/复杂 [演示](https://godbolt.org/z/8fj4WrTP6) (2认同)

归档时间:

查看次数:

2904 次

最近记录:

3 年,11 月 前