‹Functional› (вложенная привязка) проблемы с MSVC 2010

У меня есть следующий код (извините за длину):

double primeValue( const func1D &func,
                   const double lowerBound, const double upperBound,
                   const double pole )
{
    // check bounds
    if( lowerBound >= upperBound )
        throw runtime_error( "lowerBound must be smaller than upperBound!" );

    // C++0x way of writing: fullFunc(x) = func(x)/(x-a)
    func1D fullFunc =
            bind( divides<double>(),              // division of
                  bind(func, _1),                 // f(x), with _1 = x
                  bind(minus<double>(), _1, pole) ); // by x-a, with _1 = x

    // pole not in domain
    if( pole<lowerBound || pole>upperBound)
    {
        cout << "Case 1" << endl;
        return integrateSimpson( fullFunc, 1000, lowerBound, upperBound );
    }
    // pole closer to upper bound
    else if( upperBound-pole < pole-lowerBound  )
    {
       cout << "Case 2" << endl;
       // C++0x way of writing g(x) := [f(x)-f(2a-x)]/(x-a)
       func1D specialFirstFunc =
                bind( std::divides<double>(),                               // division of
                      bind(minus<double>(),                                 // numerator:
                           bind(func, _1),                                  // f(x) minus
                           bind(func, bind(minus<double>(), 2.*pole, _1))), //f(2a-x)
                      bind(minus<double>(), _1, pole) );                    // denominator: x-a
        const double trickyPart = integrateSimpson( specialFirstFunc, 1000, pole+.000001, upperBound );

        const double normalPart = integrateSimpson( fullFunc, 1000, lowerBound, 2.*pole-upperBound );
        cout << "Tricky part: " << trickyPart << endl;
        cout << "Normal part: " << normalPart << endl;
        return trickyPart + normalPart;
    }
    else // pole closer to lower bound
    {
        cout << "Case 3" << endl;
        // C++0x way of writing g(x) := [f(x)-f(2a-x)]/(x-a)
        func1D specialFirstFunc =
                 bind( std::divides<double>(),                               // division of
                       bind(minus<double>(),                                 // numerator:
                            bind(func, _1),                                  // f(x) minus
                            bind(func, bind(minus<double>(), 2.*pole, _1))), //f(2a-x)
                       bind(minus<double>(), _1, pole) );                    // denominator: x-a
         const double trickyPart = integrateSimpson( specialFirstFunc, 1000, lowerBound, pole-.00001 );

         const double normalPart = integrateSimpson( fullFunc, 1000, 2.*pole-lowerBound, upperBound );
         cout << "Tricky part: " << trickyPart << endl;
         cout << "Normal part: " << normalPart << endl;
         return trickyPart + normalPart;
    }
}

Он объединяет функции по действительной оси, которые содержат сингулярность (полюс), используя концепцию главных значений из математической области комплексного анализа. Части bind и function изменяют исходную функцию f (x) на

(f (x) -f (2 * полюс-x)) / (x-a)

Это даже дает правильный результат для моей простой функции тестового примера. По запросу я могу предоставить дополнительную информацию:

typedef std::function<double (double)> func1D;
double integrateSimpson( func1D, const size_t nSteps, const double lowerBound, const double upperBound);

Последний интегрируется с использованием простого правила интеграции Симпсона. Код может быть предоставлен, но он не имеет большого отношения к рассматриваемой проблеме.

Это нормально компилируется с GCC 4.4+ (протестировано с предварительными версиями 4.4.5 и 4.5.2, CFLAGS = "- O2 -std = c ++ 0x -pedantic -Wall -Wextra"), но вызывает внутренние ошибки заголовка (C2664) на MSVC 2010. (При необходимости могу предоставить вывод ошибок, на мой код вообще нет ссылок (!)).

Нашел ли я ошибку в MSVC?

Спасибо!


person rubenvb    schedule 24.10.2010    source источник
comment
Нашел ли я ошибку в MSVC? - Не удивлюсь, если вы это сделаете. :)   -  person casablanca    schedule 24.10.2010
comment
Это может быть связано: stackoverflow.com/questions/2425277/ Но я не понимаю, что предлагает сделать принятый ответ ...   -  person rubenvb    schedule 24.10.2010


Ответы (1)


Почему бы просто не использовать лямбду? Для такого рода целей все связующие материалы устарели.

double primeValue( const func1D &func,
                   const double lowerBound, const double upperBound,
                   const double pole )
{
    // check bounds
    if( lowerBound >= upperBound )
        throw runtime_error( "lowerBound must be smaller than upperBound!" );

    // C++0x way of writing: fullFunc(x) = func(x)/(x-a)
    auto fullFunc = [=](double d) {
        return func(d) / (d - pole);
    };

    // pole not in domain
    if( pole<lowerBound || pole>upperBound)
    {
        cout << "Case 1" << endl;
        return integrateSimpson( fullFunc, 1000, lowerBound, upperBound );
    }
    // pole closer to upper bound
    else if( upperBound-pole < pole-lowerBound  )
    {
       cout << "Case 2" << endl;
       // C++0x way of writing g(x) := [f(x)-f(2a-x)]/(x-a)
       auto specialFirstFunc = [=](double x) -> double {
           double numerator = func(x) - func(2*pole - x);
           return numerator / (x - pole);
       };
        const double trickyPart = integrateSimpson( specialFirstFunc, 1000, pole+.000001, upperBound );

        const double normalPart = integrateSimpson( fullFunc, 1000, lowerBound, 2.*pole-upperBound );
        cout << "Tricky part: " << trickyPart << endl;
        cout << "Normal part: " << normalPart << endl;
        return trickyPart + normalPart;
    }
    else // pole closer to lower bound
    {
        cout << "Case 3" << endl;
        // C++0x way of writing g(x) := [f(x)-f(2a-x)]/(x-a)
       auto specialFirstFunc = [=](double x) -> double {
           double numerator = func(x) - func(2*pole - x);
           return numerator / (x - pole);
       };
         const double trickyPart = integrateSimpson( specialFirstFunc, 1000, lowerBound, pole-.00001 );

         const double normalPart = integrateSimpson( fullFunc, 1000, 2.*pole-lowerBound, upperBound );
         cout << "Tricky part: " << trickyPart << endl;
         cout << "Normal part: " << normalPart << endl;
         return trickyPart + normalPart;
    }
}

Что касается того, действительно ли вы обнаружили ошибку в MSVC, я не знаю, но ваше решение определенно не нужно - этот код намного чище и проще в обслуживании.

person Puppy    schedule 24.10.2010
comment
Ну, поскольку большинство дистрибутивов Linux и я все еще используем GCC 4.4, лямбда-выражения не подходят. Я не думаю, что std::bind уже устарел ... Но лямбды намного короче, чем было показано мне ранее: stackoverflow.com/questions/4008369/ - person rubenvb; 24.10.2010
comment
@rubenvb: лямбда-выражения были специально введены в язык, среди прочего, потому, что связывание было отстойным. Просто добавьте к нему #ifdef. Скорее всего, библиотеки MSVC несколько устарели по сравнению с тем, что C ++ 0x теперь имеет в качестве стандарта - например, _1 определяется как std :: placeholder :: _ 1, а не просто std :: _ 1. Я проверил эту ссылку - он явно установил ссылку или значение для каждой переменной, которую он захватил, тогда как я установил мою, чтобы захватить все по значению. - person Puppy; 24.10.2010
comment
@DeadMG: Ну, обходной путь лямбда звучит неплохо, но я думаю, что внутренняя реализация в любом случае использует std::bind (дает ту же ошибку: s). Я проверил используемые #ifdef ветки, и он компилирует лямбда с использованием std::bind внутри ... - person rubenvb; 24.10.2010
comment
@ruben: Я тестировал MSVC10 и могу заверить вас, что приведенный выше код компилируется в MSVC10. - person Puppy; 24.10.2010
comment
@DeadMG: Хорошо, я попробую еще раз, как только у меня будет время. - person rubenvb; 25.10.2010
comment
У меня был еще один бит кода вложенной функции связывания, который я заменил его лямбда-эквивалентом, и теперь код отлично компилируется под MSVC 10. Еще раз спасибо! - person rubenvb; 26.10.2010