现代 C++ 是否允许 double/nested 可变参数模板扩展?
Is double/nested variadic template expansion allowed in modern C++?
我一直在尝试使用 C++ 元编程来构建诸如
f(g<0>(args...), g<1>(args...), ... g<n-1>(args...))
给定可调用对象 f
和 g
,整数 n 和可变参数 args...
然而我转向这个问题,在某些时候,我需要一个嵌套可变参数扩展:一个用于args ...和一个用于0 ... n-1,和考虑到我遇到的编译错误,我想知道 if/when 在 C++11/14/17 中是否可行,如果没有,是否有巧妙的解决方法?
下面是我想要实现的示例:
struct add
{
template<int n, class A, class B> static inline auto
f(const A & a, const B & b) -> decltype(std::get<n>(a)+b)
{ return std::get<n>(a) + b; }
};
template<class... Args> void do_stuff(const Args & ... args)
{ /* do stuff with args */ }
std::tuple<char,short,int,float,double> data = {1,3,5};
map_call<3, add>(do_stuff, data, 1); //< what I'm trying to do
// calls do_stuff(add::f<0>(data,2), add::f<1>(data,1), add::f<2>(data,1) )
// i.e. do_stuff(2,4,5)
下面给出了 map_call
的(失败的尝试)实现之一:
// what I tried:
template<class Mapped, class Indicies> struct map_call_help;
template<class Mapped, int... indices>
struct map_call_help<Mapped, std::integer_sequence<int, indices...>>
{
template<class Callable, class... Args>
static inline void f(Callable && call, Args && ... args)
{
call( Mapped::f<indices>(std::forward<Args>(args)...) ...);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2
// nested expansion fails with parse error / expected ')'
// inner expansion is: std::forward<Args>(args)...
// outer expansion is: Mapped::f<indices>(_forwarded_args_)...
}
};
template<int n, class Mapped, class Callable, class... Args>
inline void map_call(Callable && call, Args && ... args)
{
map_call_help<Mapped, std::make_integer_sequence<int, n>>::f(
std::forward<Callable>(call), std::forward<Args>(args)... );
}
integer_sequence
相关的东西需要 #include <utility>
和 C++14,或者它可以在 C++11 中实现——参见例如如果有兴趣,请回答 this question。
改变
Mapped::f<indices>
至
Mapped::template f<indices>
还有许多其他类似的错误,但那是该行的错误。 live example
我一直在尝试使用 C++ 元编程来构建诸如
f(g<0>(args...), g<1>(args...), ... g<n-1>(args...))
给定可调用对象 f
和 g
,整数 n 和可变参数 args...
然而我转向这个问题,在某些时候,我需要一个嵌套可变参数扩展:一个用于args ...和一个用于0 ... n-1,和考虑到我遇到的编译错误,我想知道 if/when 在 C++11/14/17 中是否可行,如果没有,是否有巧妙的解决方法?
下面是我想要实现的示例:
struct add
{
template<int n, class A, class B> static inline auto
f(const A & a, const B & b) -> decltype(std::get<n>(a)+b)
{ return std::get<n>(a) + b; }
};
template<class... Args> void do_stuff(const Args & ... args)
{ /* do stuff with args */ }
std::tuple<char,short,int,float,double> data = {1,3,5};
map_call<3, add>(do_stuff, data, 1); //< what I'm trying to do
// calls do_stuff(add::f<0>(data,2), add::f<1>(data,1), add::f<2>(data,1) )
// i.e. do_stuff(2,4,5)
下面给出了 map_call
的(失败的尝试)实现之一:
// what I tried:
template<class Mapped, class Indicies> struct map_call_help;
template<class Mapped, int... indices>
struct map_call_help<Mapped, std::integer_sequence<int, indices...>>
{
template<class Callable, class... Args>
static inline void f(Callable && call, Args && ... args)
{
call( Mapped::f<indices>(std::forward<Args>(args)...) ...);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2
// nested expansion fails with parse error / expected ')'
// inner expansion is: std::forward<Args>(args)...
// outer expansion is: Mapped::f<indices>(_forwarded_args_)...
}
};
template<int n, class Mapped, class Callable, class... Args>
inline void map_call(Callable && call, Args && ... args)
{
map_call_help<Mapped, std::make_integer_sequence<int, n>>::f(
std::forward<Callable>(call), std::forward<Args>(args)... );
}
integer_sequence
相关的东西需要 #include <utility>
和 C++14,或者它可以在 C++11 中实现——参见例如如果有兴趣,请回答 this question。
改变
Mapped::f<indices>
至
Mapped::template f<indices>
还有许多其他类似的错误,但那是该行的错误。 live example