是否有可能在c ++中使回调函数返回一个值?

时间:2017-09-27 16:27:30

标签: c++

我有一个圆形结构和一个存储圆圈的列表:

struct circle
{
    float r;
    int id;
};
list<circle> circleList;

我正在使用Tinyxml解析带有圆圈(半径和id)的信息的xml文档,然后将其存储在列表中:(这是在主函数中)

circle c;

for(TiXmlElement* e = objectTree; e != NULL; e = e->NextSiblingElement())
{
    c.r = atof(e->Attribute("r"));
    c.id = atoi(e->Attribute("id"));

    circleList.push_back(c);
}

它运行正常,我使用for_each打印值并且它有效,圆圈存储在列表中。但在代码的某些方面,我需要得到每个圆的半径。我试着在main函数中执行此操作,就在将循环存储在列表中的for循环之后:

float radius = for_each(circleList.begin(), circleList.end(), returnRadius);

这是回调函数:

float returnRadius(circle &data)
{
    return data.r;
}

但是我得到了很多错误,可能是因为我创建了一个名为radius的值,并尝试将for_each返回的值存储在其中,这是完全错误的,我知道。但我的目的是找到一种方法来获取回调函数returnRadius返回的值。有没有办法做到这一点?

当我尝试这样做时:

float radius = for_each(circleList.begin(), circleList.end(), returnRadius);

我收到这些错误:

error: cannot convert ‘float (*)(circle&)’ to ‘float’ in initialization
float radius = for_each(circleList.begin(), circleList.end(), returnRadius);

我理解,因为我试图让for_each函数返回半径,但我真正想要的(并且不知道该怎么做)是回调函数返回半径,毕竟,它是正在检索此信息的回调

3 个答案:

答案 0 :(得分:5)

我说你过度复杂了。

for (const auto &it : circleList)
{
    // Do whatever you wand with `it.r` here.
}

答案 1 :(得分:1)

float radius = for_each(circleList.begin(), circleList.end(), returnRadius);

for_each不会返回任何内容。它为每个值调用returnRadius,现在就完成了。正是你告诉它要做的事情。如果你想做的不仅仅是为每个项目调用returnRadius,那么你已经向编译器谎报了你希望它为每个项目做些什么。

auto print_radius = [](const circle &data) {
    std::cout << returnRadius(data) << '\n';
};
std::for_each(circleList.begin(), circleList.end(), print_radius);

一般来说,我会避免std::for_each。它非常整洁,但令代码混淆不清。

<小时/> 如果您正在使用std::for_each,那么了解boost::transform_iterator也很有趣。它是这样的:

//make iterators that transform circles to radius' on the fly
auto first = boost::make_transform_iterator(circleList.begin(), returnRadius); 
auto last = boost::make_transform_iterator(circleList.end(), returnRadius);
//copy these radius' to cout.
std::copy(first, last, std::ostream_iterator(std::cout);

答案 2 :(得分:0)

  

是否可以在c ++中使回调函数返回一个值?

你的标题与问题的主体没什么关系,但我关注它,并以通常的方式理解callbacks

这可能取决于您的C ++版本。我希望你至少使用C ++ 11,然后你可以拥有lambda expressionsstd::function - s和<algorithm>

以下是如何使用std::transform(在其他编程语言中通常称为map)使用lambda表达式获取区域列表(实际上是std::list<float>):

 auto areaList = std::transform(circleList.begin(), circleList.end(),
                                [] (const circle&c) 
                                { return c.r*c.r*M_PI; });

(你应该能够适应你的TinyXML)

你应该读一个好的C ++ 11 programming book

您可以阅读SICP以及closureanonymous functions wikipages