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)
我必须考虑这些限制:
是否可以在 C++14 中做类似的事情(最好是 C++14,但好奇新版本中的解决方案是什么)?
编辑:清理了最初的马虎伪代码。
在调用站点上使用稍微不同的语法,您可以通过引用数组来实现:
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)
如果将函数改为函子,则可以在函子类型的主体中引入参数包。
首先创建一个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)
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)
这是c++17;它可以在c++14中完成,它只需要更多的输入,而且我很懒(主要替换折叠表达式)。
这要求调用站点有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)
这是c++20,但您可以通过编写参数包解包器向后移植到c++14。
这里的技巧是foo<Foo,7>()返回一个知道它7 Foo准确获取对象的函数对象。
在c++14中,我们可以:
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 的版本)。
| 归档时间: |
|
| 查看次数: |
2904 次 |
| 最近记录: |