使用参数包扩展调用具有可变参数的函数,但修改第i个参数

时间:2015-05-18 17:02:08

标签: c++ c++11 variadic-templates variadic-functions

假设我们有一个功能

template<typename T, typename... Args>
T f(Args... args);

我们希望在其他功能中调用f

template<typename... Args>
void bar(Args... args) {
    // f(args1, ..., args(i-1), "modified argsi", args(i+1), ..., argsn);
}

并修改所有i的{​​{1}} - 参数(并保持其他参数不变)。 i = 1, ..., n会返回结果,我希望将所有f个结果存储在n中。

我们怎么能这样做?

4 个答案:

答案 0 :(得分:3)

使用I编译时间值,您可以执行以下操作:

namespace detail
{

    template<std::size_t I>
    struct impl
    {
        template <typename TUPLE>
        auto operator() (TUPLE&& t) { return std::get<I>(t); }
    };

    template<>
    struct impl<2>
    {
        template <typename TUPLE>
        auto operator() (TUPLE&& t) { return std::get<2>(t) + 40; }
    };

    template <std::size_t... Is, typename TUPLE>
    void bar(std::index_sequence<Is...>, TUPLE&& Tuple) {
        return f(impl<Is>{}(std::forward<TUPLE>(Tuple))...);
    }

}

template<typename... Args>
void bar(Args... args) {
    detail::bar(std::index_sequence_for<Args...>(), std::forward_as_tuple(args...));
}

Live Demo

使用i运行时值:

namespace detail
{

    template<class T>
    auto modifier(T&& arg, std::size_t i, std::size_t pos) {
        if (i == pos)
            return arg + 40; // Or appropriate modification.
        else
            return std::forward<T>(arg);
    }

    template <std::size_t... Is, typename... Args>
    void bar(std::size_t pos, std::index_sequence<Is...>, Args&&... args) {
        return f(modifier(std::forward<Args>(args), Is, pos)...);
    }

}

template<typename... Args>
void bar(std::size_t pos, Args&&... args) {
    detail::bar(pos, std::index_sequence_for<Args...>(), std::forward<Args>(args)...);
}

Live Demo

答案 1 :(得分:1)

好吧,如果要避免分支,查找表就可以完成工作。粗略草图:

#include <tuple>
#include <utility>
#include <iostream>

void foo(std::string a, std::string b, std::string c) {
    std::cout << a << '|' << b << '|' << c;
}

template <typename, typename> struct passerAux;
template <std::size_t... prevI, std::size_t... followI>
struct passerAux<std::index_sequence<prevI...>, std::index_sequence<followI...>> {
    template <typename... Args>
    static decltype(auto) passer( Args&&... args ) {
        auto tuple = std::forward_as_tuple(std::forward<Args>(args)...);
        return foo( std::forward<std::tuple_element_t<prevI, decltype(tuple)>>(std::get<prevI>(tuple))...,
                    "ModifiedArg",
                    std::forward<std::tuple_element_t<followI+sizeof...(prevI)+1, decltype(tuple)>>(std::get<followI+sizeof...(prevI)+1>(tuple))... );
    }
};

template <typename... Args, std::size_t... indices>
decltype(auto) passer( std::size_t i, std::index_sequence<indices...>, Args&&... args ) {
    void(*lookup[])(Args&&...) {
        passerAux<std::make_index_sequence<indices>, std::make_index_sequence<sizeof...(Args)-indices-1>>::passer...
    };
    return lookup[i](std::forward<Args>(args)...);
}

template <typename... Args>
decltype(auto) passer( std::size_t i, Args&&... args ) {
    return passer(i, std::make_index_sequence<sizeof...(Args)>{}, std::forward<Args>(args)... );
}

int main() {
    passer(0, "A", "B", "C"); std::cout << '\n';
    passer(1, "A", "B", "C"); std::cout << '\n';
    passer(2, "A", "B", "C");
}

Demo

答案 2 :(得分:0)

根据您的评论,我认为(?)您想要的是:

namespace detail {
    template <typename Arg, typename Idx>
    auto modify_arg(Arg&& arg, Idx )
    {
        // TODO: whatever modifications you want to make
        // to the argument indexed by Idx
    }

    template <size_t... Is, typename... Args>
    void bar(std::index_sequence<Is...>, Args&&... args) 
    {
        // Don't know where 'T' comes from - you still
        // need that for your f()
        f(modify_arg(std::forward<Args>(args),
                     std::integral_constant<size_t, Is>{})...
                     );
    }
}

template<typename... Args>
void bar(Args&&... args) {
    detail::bar(std::index_sequence_for<Args...>{},
                std::forward<Args>(args)...
                );
}

答案 3 :(得分:0)

非编译时实现可能是:

#include <iostream>
#include <type_traits>

// Replace a value at a position
// =============================

template<typename R>
struct Replace {
    int i;
    R replacement;
    Replace(int i, R&& replacement)
    :   i(i), replacement(replacement)
    {}

    template<typename T>
    T&& operator() (T&& value) noexcept {
        return (0 == i--)
            ? std::forward<T>(replacement)
            : std::forward<T>(value);
    }
};

template <typename R, typename... Args>
Replace<R> replace(int i, R&& replacement) {
    return Replace<R>(i, std::forward<R>(replacement));
}

// Test: Print values
// ==================

template<typename T, typename... Args>
void print(const T&, const Args&...);

template<typename T, typename... Args>
void print(const T& value) {
    std::cout << value << '\n';
}

template<typename T, typename... Args>
void print(const T& value, const Args&... args) {
    std::cout << value << '\n';
    print(args...);
}


// Test: Function
// ==============

template<typename... Args>
void f(Args... args) {
    // Note, 'print(replace(1, 7)(args)...);' will not work.
    auto r = replace(1, 7);
    print(r(args)...);
}


int main()
{
    f(1, 2, 3);
}