使用可变参数模板建立索引

发布于 2024-11-03 07:04:59 字数 789 浏览 1 评论 0原文

假设我有一个正在展开的参数包,例如

template<typename... P> void f(P...&& args) {
    some_other_func(std::forward<P>(args)...);
}

现在假设我还有这些对象需要执行的其他一些次要功能。

template<typename T> T&& some_func(T&& ref) {
    // replace with actual logic
    return std::forward<T>(ref);
}

我通常会替换为

template<typename... P> void f(P...&& args) {
    some_other_func(some_func(args)...);
}

但是,如果 some_func 需要有关参数的更多信息而不仅仅是其类型,例如它在参数包中的数字位置,我该怎么办?这样我就可以将其扩展到

some_other_func(some_func(arg1), some_func(arg2));

而不是扩展到?

some_other_func(some_func(arg1, 1), some_func(arg2, 2));

例如,

Let's say that I have a parameter pack I'm unrolling, e.g.

template<typename... P> void f(P...&& args) {
    some_other_func(std::forward<P>(args)...);
}

Now let's say that I have some other minor function that these objects need to go through.

template<typename T> T&& some_func(T&& ref) {
    // replace with actual logic
    return std::forward<T>(ref);
}

I would normally just replace with

template<typename... P> void f(P...&& args) {
    some_other_func(some_func(args)...);
}

But what do I do if some_func requires more information about the parameter than just it's type, like for example, it's position numerically in the parameter pack? So that instead of expanding to

some_other_func(some_func(arg1), some_func(arg2));

I could mke it expand to

some_other_func(some_func(arg1, 1), some_func(arg2, 2));

for example?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

还如梦归 2024-11-10 07:04:59

我知道我以前解决过这个问题,但不记得是怎么解决的。哦,好吧,这是一个新鲜的外观。

数字序列可以使用 std::get 转换为参数序列,因此更为基础。因此,假设我需要实现某种自定义工具,数字包生成器似乎是一个不错的选择。

(啊,这太乏味了。我确实看了 Howard 的答案并了解了 forward_as_tuple,但该函数在我的编译器或 ideone.com 上还不存在,所以废话。有很多我仍然需要弄清楚一些事情,这无疑是有史以来最糟糕的函数式语言之一。)

http://ideone.com/u5noV

#include <tuple>

// Generic pack array (metacontainer)
template< typename T, T ... seq > struct value_sequence {
    // Append a value to the array (metafunction)
    template< T val > struct append
        { typedef value_sequence< T, seq..., val > type; };
};

// Generate a sequential array (metafunction)
template< size_t N >
struct index_sequence {
    typedef typename index_sequence< N - 1 >::type
                      ::template append< N - 1 >::type type;
};

template<>
struct index_sequence< 0 >
    { typedef value_sequence< size_t > type; };

// Generate indexes up to size of given tuple (metafunction)
template< typename T >
struct index_tuple {
    typedef typename index_sequence< std::tuple_size< T >::value
                                   >::type type;
};

// The magic function: passes indexes, makes all the function calls
template< typename F, typename G,
          typename T, size_t ... N >
void compose_with_indexes_helper( F f, G g, T args,
        value_sequence< size_t, N ... > ) {
    f( g( std::get< N >( args ), N ) ... );
}

template< typename F, typename G, typename ... T >
void compose_with_indexes( F f, G g, T && ... args ) {
    typedef std::tuple< T && ... > tuple_t;
    compose_with_indexes_helper
//        forwarding seems broken on ideone.com/GCC 4.5.1, work around.
//        ( f, g, std::forward_as_tuple( std::forward( args ) ... ) );
        ( f, g, tuple_t( args ... ), typename index_tuple< tuple_t >::type() );
}

I know I've solved this before but can't recall how. Oh well, here's a fresh look.

The sequence of numbers can be translated into the argument sequence using std::get, so it is more fundamental. So, assuming that I need to implement some kind of custom tool, a number pack generator seems like a good choice.

(Gah, this was incredibly tedious. I did peek at Howard's answer and learned about forward_as_tuple, but that function doesn't even exist yet on my compiler or ideone.com, so blah. There are a lot of things I still need to get straight, and this is certainly one of the worst functional languages ever invented.)

http://ideone.com/u5noV

#include <tuple>

// Generic pack array (metacontainer)
template< typename T, T ... seq > struct value_sequence {
    // Append a value to the array (metafunction)
    template< T val > struct append
        { typedef value_sequence< T, seq..., val > type; };
};

// Generate a sequential array (metafunction)
template< size_t N >
struct index_sequence {
    typedef typename index_sequence< N - 1 >::type
                      ::template append< N - 1 >::type type;
};

template<>
struct index_sequence< 0 >
    { typedef value_sequence< size_t > type; };

// Generate indexes up to size of given tuple (metafunction)
template< typename T >
struct index_tuple {
    typedef typename index_sequence< std::tuple_size< T >::value
                                   >::type type;
};

// The magic function: passes indexes, makes all the function calls
template< typename F, typename G,
          typename T, size_t ... N >
void compose_with_indexes_helper( F f, G g, T args,
        value_sequence< size_t, N ... > ) {
    f( g( std::get< N >( args ), N ) ... );
}

template< typename F, typename G, typename ... T >
void compose_with_indexes( F f, G g, T && ... args ) {
    typedef std::tuple< T && ... > tuple_t;
    compose_with_indexes_helper
//        forwarding seems broken on ideone.com/GCC 4.5.1, work around.
//        ( f, g, std::forward_as_tuple( std::forward( args ) ... ) );
        ( f, g, tuple_t( args ... ), typename index_tuple< tuple_t >::type() );
}
迷迭香的记忆 2024-11-10 07:04:59

这有点复杂。但这里是使用 libc++ 的几个私有实用程序的代码的工作原型,可以在
<__tuple>

#include <iostream>
#include <tuple>

template<typename T>
int
some_func(T&& ref, size_t I)
{
    std::cout << "ref = " << ref << ", I = " << I << '\n';
    return 0;
}

template<typename... T, size_t ...Indx>
void
some_other_func(std::tuple<T...> ref, std::__tuple_indices<Indx...>) {
    // replace with actual logic
    std::__swallow(some_func(std::get<Indx>(ref), Indx)...);
}


template<typename... P>
void
f(P&&... args)
{
    some_other_func(std::forward_as_tuple<P...>(std::forward<P>(args)...),
                    typename std::__make_tuple_indices<sizeof...(P)>::type());
}

int main()
{
    f("zero", "one", "two", "three");
}

ref = zero, I = 0
ref = one, I = 1
ref = two, I = 2
ref = three, I = 3

It is a little convoluted. But here is a working prototype of your code using several private utilities of libc++, found in
<__tuple>, and <tuple>.

#include <iostream>
#include <tuple>

template<typename T>
int
some_func(T&& ref, size_t I)
{
    std::cout << "ref = " << ref << ", I = " << I << '\n';
    return 0;
}

template<typename... T, size_t ...Indx>
void
some_other_func(std::tuple<T...> ref, std::__tuple_indices<Indx...>) {
    // replace with actual logic
    std::__swallow(some_func(std::get<Indx>(ref), Indx)...);
}


template<typename... P>
void
f(P&&... args)
{
    some_other_func(std::forward_as_tuple<P...>(std::forward<P>(args)...),
                    typename std::__make_tuple_indices<sizeof...(P)>::type());
}

int main()
{
    f("zero", "one", "two", "three");
}

ref = zero, I = 0
ref = one, I = 1
ref = two, I = 2
ref = three, I = 3
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文