c++ - 模板/预处理器 hackery 可以用于支持参数列表中间的可变参数吗?

标签 c++ templates c++11 macros

我偶然发现了这样的旧代码:

void dothing(bool testBool,
               const std::string& testString1,
               const std::string& file,
               int line,
               const std::string& defaultString = "")
{
     // do something...
}

void dothings(bool testBool,
               const std::string& testString1,
               const std::string& testString2,
               const std::string& file,
               int line,
               const std::string& defaultString = "")
{
    dothing(testBool, testString1, file, line, defaultString);
    dothing(testBool, testString2, file, line, defaultString);
}

void dothings(bool testBool,
               const std::string& testString1,
               const std::string& testString2,
               const std::string& testString3,
               const std::string& file,
               int line,
               const std::string& defaultString = "")
{
   dothings(testBool, testString1, testString2, file, line, defaultString);
   dothing(testBool, testString3, file, line, defaultString);
}

void dothings(bool testBool,
               const std::string& testString1,
               const std::string& testString2,
               const std::string& testString3,
               const std::string& testString4,
               const std::string& file,
               int line,
               const std::string& defaultString = "")
{
   dothings(testBool, testString1, testString2, testString3, file, line, defaultString);
   dothing(testBool, testString1, file, line, defaultString);
}

这很荒谬,我正在尝试将其重构为:

 void dothings(bool testBool,
              std::initializer_list<std::string> testStrings,
              const std::string& file,
              int line,
              const std::string& defaultString = "")
{
    for(auto iter = testStrings.begin(); iter != testStrings.end(); ++iter)
    {
        dothing(testBool, *iter, file, line, defaultString);
    }
}

问题是这些函数被大量使用,我想编写一个宏或模板,使所有以前的函数构造一个包含所有测试字符串的字符串的初始化列表,并将它们传递给一项新功能。我想写这样的东西:

#define dothings(testBool, (args), file, line) dothings(testBool, {args}, file, line)

我不太关心这些函数中的默认字符串,但如果有办法支持它,那就太好了。

我只能使用 c++11 编译器和 boost。

我无法对这些函数的参数重新排序。

我看过一些关于可变参数宏的有趣帖子,但只是没有点击如何将它们应用到这种情况。

最佳答案

这只是可能的解决方案之一,可以改进它来检测末尾是否有额外的默认字符串(通过一些其他元编程技术和 SFINAE)。这个利用了 indices trick将参数列表分成两个子序列:一个用于三个尾随参数,一个用于字符串本身。最终,每个字符串都与剩余的参数配对,并且对函数 dothing 的调用是 expanded .

void dothing(bool testBool
           , const std::string& str
           , const std::string& file
           , int line
           , const std::string& defaultString)
{
    // processing of a single str
}

template <typename... Args, std::size_t... Is>
void dothings(bool testBool, std::index_sequence<Is...>, Args&&... args)
{
    auto tuple = std::make_tuple(std::forward<Args>(args)...);
    using expander = int[];
    static_cast<void>(expander{ 0, (dothing(testBool, std::get<Is>(tuple)
                               , std::get<sizeof...(Args)-3>(tuple)
                               , std::get<sizeof...(Args)-2>(tuple)
                               , std::get<sizeof...(Args)-1>(tuple)), 0)... }); 
}

template <typename... Args>
void dothings(bool testBool, Args&&... args)
{
    dothings(testBool
           , std::make_index_sequence<sizeof...(Args)-3>{}
           , std::forward<Args>(args)...); 
}

DEMO

关于c++ - 模板/预处理器 hackery 可以用于支持参数列表中间的可变参数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31794496/

相关文章:

c++ - 错误 : . 是什么意思。 Xcode/Clang 中的 ."bytes to alignment boundary"?

c++ - 如何使用二维矩形缓冲区沿二维线段限制搜索空间

c++ - 如何在 C++ 中获取文件的大小?

c++ - 泛型编程需要在派生类中重新声明基类成员函数

c++ - 如何用android ndk和eclipse编译c++11代码?

c++ - 共同的初始序列和比对

c++ - 为什么模板化的右值引用接受左值?

c# - 如果C++中的DLL不支持二进制封装,那么什么时候才可以使用它们呢?

c++ - 是否有一些技巧可以让我将流操纵器传递给可变参数模板函数?

不同模板之间的c++复制构造函数