C 11递归变异模板

c++11 recursive variadic templates

本文关键字:变异 递归      更新时间:2023-10-16

我正在尝试了解递归变异模板的工作方式。

#include <iostream>
template<typename T>
static inline void WriteLog(T&& msg) {
    std::wcout << std::forward<T>(msg);
}
template<typename T, typename... Ts>
static void WriteLog(T&& msg, Ts&&... Vals) {
    WriteLog(std::forward<T>(msg));
    WriteLog(std::forward<Ts>(Vals)...);
    std::wcout << "n**End**";
}
int main() {
    WriteLog("apple, ", "orange, ", "mango");
}

输出:

apple, orange, mango
**End**
**End**

我只期望一个**End**。为什么打印两次?

呼叫树:

 WriteLog("apple, ", "orange, ", "mango");
       ->WriteLog("apple, ");
            -> std::wcout << "apple, ";
       ->WriteLog( "orange, ", "mango");
            ->WriteLog("orange, ");
                 -> std::wcout << "orange, ";
            ->WriteLog( "mango");
                 -> std::wcout << "mango";
            ->std::wcout << "n**End**";
       ->std::wcout << "n**End**";

完成WriteLog(std::forward<Ts>(Vals)...);的递归调用时,它必须执行下一个语句。此功能称为两次(一次用于"apple",一次用于"orange"),因此编写了"**End**"的两个打印量。

"mango"的最后一个递归电话直接到第一个过载,因为包装中只剩下一个参数。

**End**是为

的调用打印的
  • WriteLog("apple, ", "orange, ", "mango");中的CC_8
  • WriteLog("orange, ", "mango");(带有 WriteLog(std::forward<Ts>(Vals)...);)中的 WriteLog("apple, ", "orange, ", "mango")

我会和你老实,我一直在编写C 11模板代码4年,而我仍然很难记住如何匹配空参数包...

这个小技巧完全避免了递归模板扩展:(编辑:重新编写以支持零参数和自动逗号分离器插入)

#include <iostream>
namespace detail {
    struct writer
    {
        template<class T>
        void operator()(const T& t) {
            if (_first) {
                _first = false;
            }
            else {
                std::cout << ", ";
            }
            std::cout << t;
        }
    private:
        bool _first = true;
    };
    // non-template overload to catch no-parameter case
    void do_write(writer&&)
    {
    }
    // general case. Note w is passed by r-value reference
    // to allow the caller to construct it in-place        
    template<typename T, typename...Ts>
    void do_write(writer&& w, const T& t, Ts&&...ts)
    {
        w(t);
        do_write(std::forward<writer>(w), std::forward<Ts>(ts)...);
    }

}
// method 1 - no recursion
template<typename... Ts>
void WriteLog1(Ts&&... Vals) {
    // expand one call for each parameter
    // use comma operator to ensure expression result is an int
    detail::writer write;
    using expander = int[];
    expander { 0, (write(std::forward<Ts>(Vals)), 0)... };
    // write the final linefeed
    std::cout << std::endl;
}
// method 2 - recursion
template<typename...Ts>
void WriteLog2(Ts&&...ts)
{
    detail::do_write(detail::writer(), std::forward<Ts>(ts)...);
    std::cout << std::endl;
}
int main() {
    WriteLog1("apple", "orange", "mango");
    WriteLog1("apple", "orange");
    WriteLog1("apple");
    WriteLog1("apple", 1.0, "orange", 1L, "mango", 2.6f);
    WriteLog1(); // test pathalogical case
    WriteLog2("apple", "orange", "mango");
    WriteLog2("apple", "orange");
    WriteLog2("apple");
    WriteLog2("apple", 1.0, "orange", 1L, "mango", 2.6f);
    WriteLog2(); // test pathalogical case
    return 0;
}

输出:

apple, orange, mango                                                                                                                                             
apple, orange                                                                                                                                                    
apple                                                                                                                                                            
apple, 1, orange, 1, mango, 2.6                                                                                                                                  
apple, orange, mango                                                                                                                                             
apple, orange                                                                                                                                                    
apple                                                                                                                                                            
apple, 1, orange, 1, mango, 2.6
>