2

我有以下有效的代码,但我对它的工作原理感到困惑。

template<typename ...Args>
void print(Args&&... args) {
    (std::cout << ... << std::forward<Args>(args)) << '\n';
}
int main()
{
    print(1,2.0,"3");
}

输出:

123

我的困惑:

我希望打印 321。

我想要这个订单:

cout << forward(args) << ... 

但我无法编译...

4

4 回答 4

3

折叠表达式尊重您使用的运算符的优先级和关联性。但是对于某些运算符,您可以进行更多创造性的左右折叠。唯一要考虑的变量是操作数的顺序。C++17 引入了赋值运算符左右两边的发生前关系,因此它们的行为更加直观。右侧以及所有相关的副作用必须首先发生。

因此,您的问题的完全独立的解决方案可能如下所示:

template <typename... Args>
void print(Args&& ...args) {
   int dum = 0;
   (... = (std::cout << args, dum));
}

来了,直播

它使用逗号进行打印,同时dum以强制我们想要的评估顺序的方式分配给自己。

于 2019-04-19T15:36:59.597 回答
3

的位置...指定左或右关联性,但不会更改参数的顺序 - 它允许您在 和 之间(std::cout << x) << y进行选择std::cout << (x << y)。后者可能不会编译。

如果你想以相反的顺序打印值,你需要使用一些技巧。这是示例:

#include <type_traits>
#include <iostream>

template <typename T>
struct ReversePrinter
{
    ReversePrinter(T val) : val(val) { }

    template <typename U>
    ReversePrinter<T> operator<<(const ReversePrinter<U>& other) const
    {
        std::cout << other.val;
        return *this;
    }

    T val;
};

template <typename T>
std::ostream& operator<<(std::ostream& stream, const ReversePrinter<T>& val)
{
    return stream << val.val;
}

template <typename... Args>
void print(Args... args)
{
    std::cout << (ReversePrinter(args) << ...);
}

int main()
{
    print(100, 200, 300.0); //prints 300200100
}
于 2019-04-19T14:57:29.323 回答
2

有了一些技巧,(目前没有更好的方法)您可以执行以下操作:

不确定是否有任何直接的方法

// Your original function
template<typename ...Args>
void print(Args&&... args) {
    (std::cout << ... << std::forward<Args>(args)) << '\n';
}

template<typename ...Args>
struct changeorder;

template<>
struct changeorder<>
{
    template<typename ...OtherArgs>
    static void invoke(OtherArgs const&... otherargs)
    {
        print(otherargs...);
    }
};

template<typename T, typename ...Args>
struct changeorder<T, Args...> 
{
    template<typename ...OtherArgs>
    static void invoke(T const& t, Args const&... args, 
                      OtherArgs const&... otherargs)
    {
        // 1st parameter send first
        changeorder<Args...>::invoke(args..., t, otherargs...);
    }
};

template<typename A, typename ...Args>
void reverseprint(A const& a, Args const&... args)
{
    changeorder<Args...>::invoke(args..., a);
}

Demo Here

于 2019-04-19T14:20:33.907 回答
2

模板魔术的标准首选解决方案是std::index_sequence.
为了使参数可索引,一个使用std::tuple.

template <std::size_t... N, class T>
void print_reverse_impl(std::index_sequence<N...>, std::ostream& os, T t) {
    (os << ... << std::get<std::tuple_size_v<T> - N - 1>(t));
}

template <class... T>
void print_reverse(std::ostream& os, T&&... t) {
    print_reverse_impl(std::make_index_sequence<sizeof...(t)>(), os, std::forward_as_tuple(t...));
}

不过,如果你static_for()的工具箱中有(你真的应该),这更简单:

template <class... T>
void print_reverse(std::ostream& os, T&&... t) {
    static_for<sizeof...(t)>([&](auto n){
        os << std::get<sizeof...(t) - n - 1>(std::forward_as_tuple(t...));
    });
}

使用 C++20,也可以这样写:

void print_reverse(std::ostream& os, auto&&... t) {
    [&]<auto... N>(std::index_sequence<N...>, auto all){
        (os << ... std::get<sizeof...(t) - N - 1>(all));
    }(std::make_index_sequence<sizeof...(t)>(), std::forward_as_tuple(t...));
}

顺便说一句,我删除了对 的所有调用std::forward,因为无论如何这些右值引用都会被标准库缩减为左值引用。

于 2019-04-19T15:10:41.200 回答