首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >修改传递给该函数内部变量函数的参数

修改传递给该函数内部变量函数的参数
EN

Stack Overflow用户
提问于 2018-06-05 06:53:03
回答 2查看 135关注 0票数 1

以下代码无法编译。如何修改get_numbers_from_line_variadic中的args变量

非变量版本get_numbers_from_line说明了变量版本应该实现什么,然而,变量版本的参数可能具有不同的类型。

代码语言:javascript
复制
#include <iostream>
#include <sstream>
#include <string>

template<typename... ArgTypes>
void get_numbers_from_line_variadic(std::string line, ArgTypes&... args)
{
   std::istringstream iss(line);

   for (auto& arg : {args...})
      iss >> arg;
}

void get_numbers_from_line(std::string line, int& a, int& b)
{
    std::istringstream iss(line);
    iss >> a;
    iss >> b;
}

int main()
{
    int a, b;
    get_numbers_from_line("1 2", a, b);
    get_numbers_from_line_variadic("1 2", a, b);

    std::cout << "a = " << a << std::endl;
    std::cout << "b = " << b << std::endl;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-05 07:27:49

只有在没有parameter pack expansion时才会调用第一个重载(基函数)。第二个重载是一个递归变量函数,它将包的头部与尾部(参数包的其余部分)分开。这使得只递归地传递尾部,直到它变为空。

代码语言:javascript
复制
#include <iostream>
#include <sstream>
#include <string>

void get_numbers_from_line(std::istringstream&){} // base function

template<typename T, typename... Ts>
void get_numbers_from_line(std::istringstream& iss, T&& head, Ts&&... tail) // recursive variadic function
{
    iss >> head;
    get_numbers_from_line(iss, std::forward<Ts>(tail)...);
}

template<typename... Ts>
void get_numbers_from_line(std::string line, Ts&&... args)
{
    std::istringstream iss(line);
    get_numbers_from_line(iss, std::forward<Ts>(args)...);
}

int main()
{
    double a;
    int b, c;
    get_numbers_from_line("-0.1 2 3", a, b, c);

    std::cout << "a = " << a << std::endl;
    std::cout << "b = " << b << std::endl;
    std::cout << "c = " << c << std::endl;
}

Fold expression版本(从C++17开始):

代码语言:javascript
复制
template<typename... Ts>
void get_numbers_from_line(std::string line, Ts&&... args)
{
    std::istringstream iss(line);
    (iss >> ... >> std::forward<Ts>(args));
}
票数 2
EN

Stack Overflow用户

发布于 2018-06-05 07:20:16

这里的问题是,当一个类型直接从带括号的初始化列表推导出来时,推导出的类型是std::initializer_list的特殊化,并且std::initializer_list只允许const访问它的元素。

更详细地说,基于范围的for语句类似于循环:

代码语言:javascript
复制
{
    auto&& range = {args...};      // std::initializer_list<int>&&
    auto iter = range.begin();     // const int*
    auto end  = range.end();       // const int*
    for (; iter != end; ++iter) {
        auto& arg = *iter;         // const int&
        iss >> arg;                // ERROR
    }
}

因为std::initializer_list<T>::iteratorconst T*

您将需要更直接地处理函数参数。

正如注释中所指出的,如果您使用的是C++17 (或更高版本),则可以使用折叠表达式。

代码语言:javascript
复制
{
    std::istringstream iss(line);
    (iss >> ... >> args);
}

如果使用C++11或C++14,则可以改用虚拟数组初始化技巧:

代码语言:javascript
复制
{
    std::istringstream iss(line);

    // Note (expr, 0) to discard expression result and supply int
    // for the array, and final 0 in case sizeof...(args)==0
    int dummy[] = { (iss >> args, 0)..., 0 };
    static_cast<void>(dummy); // avoid unused variable warning
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50689825

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档