Variadic函数和C ++ 11,将对象作为参数传递

时间:2014-08-05 12:38:21

标签: c++ gcc c++11 cocos2d-x marmalade

我有这样的麻烦,当我们开始使用新的C ++ 11时,编译器(GCC)说这段代码错了,但它在旧版本中运行正常:(

std::list<CCPoint> createPointArray(int count, ...) {
    CCPoint val;
    std::list<CCPoint*> arr;

    va_list vl;
    va_start(vl,count);
    for (int i=0;i<count;i++)
    {
        val = va_arg(vl,CCPoint*);
        arr.push_back(*val);
    }
    va_end(vl);

    return arr;
}

这就是方式,我正在使用它:

createPointArray(3, &CCPoint(1.3,2.7), &CCPoint(1.5,1.75), &CCPoint(1.9,1.3))

编译器告诉我下一步:

Error   486 error : taking address of temporary [-fpermissive] (col 57) 

为什么&amp; CCPoint(1.3,2.7)出现问题?如何更改此代码以使其适用于C ++ 11及更早版本?

P.S。:我正在使用Marmalade 7.3.1,Visual Studio 2010,cocos2d-x v2.2.1

4 个答案:

答案 0 :(得分:3)

如果您正在使用C ++ 11,请不要首先编写此功能。新的初始化列表构造函数将为您处理它:

std::list<CCPoint> l { CCPoint(1.3,2.7), CCPoint(1.5, 1.75), CCPoint(1.9, 1.3) };

如果由于某种原因想要继续使用这个可变参数函数,你可以停止编译器抱怨你没有获取临时地址而获取临时地址。

你可以通过值传递对象,尽管ecatmur指出这是实现定义的(如果复制和移动构造函数和析构函数都是微不足道的话应该没问题):

std::list<CCPoint> m = createPointArray(3, CCPoint(1.3,2.7),
                                        CCPoint(1.5,1.75), CCPoint(1.9,1.3));

(你已经在你的函数中将val声明为CCPoint实例 - 而不是指针 - 只需更改va_arg类型即可。)

否则,您可以直接传递双值:

std::list<CCPoint> m = createPointArray(3, 1.3, 2.7, 1.5, 1.75, 1.9, 1.3);

std::list<CCPoint> createPointArray(int count, ...) {
    std::list<CCPoint> arr;

    va_list vl;
    va_start(vl,count);
    for (int i=0;i<count;i++) {
        double x = va_arg(vl,double);
        double y = va_arg(vl,double);
        arr.push_back(CCPoint(x,y));
    }
    va_end(vl);

    return arr;
}

答案 1 :(得分:1)

你只是不能把一个临时的地址,究竟是什么错误说的。您可以通过传递值来轻松解决此问题:

std::list<CCPoint> createPointArray(int count, ...) {
    std::list<CCPoint> arr;

    va_list vl;
    va_start(vl,count);
    for (int i=0;i<count;i++)
        arr.push_back(va_arg(vl,CCPoint));
    va_end(vl);

    return arr;
}

createPointArray(3, CCPoint(1.3,2.7), CCPoint(1.5,1.75), CCPoint(1.9,1.3));

而且,你现在不需要这样的功能:

std::list<CCPoint> arr {CCPoint(1.3,2.7), CCPoint(1.5,1.75), CCPoint(1.9,1.3)};

更简单

答案 2 :(得分:0)

暂时使用prvalue的地址是非法的(在C ++ 03中也是非法的)。

您可以使用强制转换将值类别更改为左值:

createPointArray(3,
  &static_cast<CCPoint const&>(CCPoint(1.3,2.7)),
  &static_cast<CCPoint const&>(CCPoint(1.5,1.75)),
  &static_cast<CCPoint const&>(CCPoint(1.9,1.3)));

这将适用于C ++ 03和C ++ 11,因为临时对象在封闭的完整表达式结束之前不会被销毁。

因为您通过指针将对象传递给const,所以您应该使用va_arg(vl, CCPoint const*)提取它们。

答案 3 :(得分:0)

在C ++ 11中,只需使用initializer_list

std::list<CCPoint> l { CCPoint(1.3, 2.7), CCPoint(1.5, 1.75), CCPoint(1.9, 1.3) };

在C ++ 03中,您可能有一个数组,然后使用以下命令初始化您的列表:

const CCPoint points[] = { CCPoint(1.3, 2.7), CCPoint(1.5, 1.75), CCPoint(1.9, 1.3) };

std::list<CCPoint> l(points, points + sizeof(points) / sizeof(*points));
// or std::list<CCPoint> l(points, points + 3); // error prone
// or std::list<CCPoint> l(std::begin(points), std::end(points)); // In C++11