Accumulator_& operator()(double more)
{
    if (auto d = CoerceDouble(*val_))
        Set(+d + more);
    else
        THROW("Accumulate(double) failed");
    return *this;
}
// still inside struct Accumulator_
// various operator() implementations provide a de facto multimethod
Accumulator_& operator()(int more)
{
    if (auto i = CoerceInt(*val_))
        Set(+i + more);
    else if (auto d = CoerceDouble(*val_))
        Set(+d + more);
    else
        THROW("Accumulate(int) failed");
    return *this;
}
static bool
JSValToMatrixElts(JSContext* cx, const jsval& val,
                  double* (&elts)[N], nsresult* rv)
{
    JSObject* obj;
    jsuint length;

    if (JSVAL_IS_PRIMITIVE(val) ||
        !(obj = JSVAL_TO_OBJECT(val)) ||
        !JS_GetArrayLength(cx, obj, &length) ||
        N != length) {
        // Not an array-like thing or wrong size
        *rv = NS_ERROR_INVALID_ARG;
        return false;
    }

    for (PRUint32 i = 0; i < N; ++i) {
        jsval elt;
        double d;
        if (!JS_GetElement(cx, obj, i, &elt)) {
            *rv = NS_ERROR_FAILURE;
            return false;
        }
        if (!CoerceDouble(elt, &d)) {
            *rv = NS_ERROR_INVALID_ARG;
            return false;
        }
        if (!FloatValidate(d)) {
            // This is weird, but it's the behavior of SetTransform()
            *rv = NS_OK;
            return false;
        }
        *elts[i] = d;
    }

    *rv = NS_OK;
    return true;
}