Как вызвать std :: unique с пользовательским предикатом в C ++ 03? - PullRequest
2 голосов
/ 05 ноября 2019

Я видел этот пример того, как сделать это в C ++ 11:

std::unique(v.begin(), v.end(), [](float l, float r)
{ 
  return std::abs(l - r) < 0.01; 
});

Однако, это терпит неудачу для меня в C ++ 03:

error: template argument for 'template<class _FIter, class _BinaryPredicate> _FIter std::unique(_FIter, _FIter, _BinaryPredicate)' uses local type 'CRayTracer::myFunc()::<lambda(float, float)>'

Как можноЯ делаю это в C ++ 03? Я думаю, что Lambdas, возможно, уже существовали, и функторы / функциональные объекты существовали, верно? Просто искать простое решение не нужно расширять - оно будет использоваться только здесь.

Вот пример кода, который не будет компилироваться для меня:

#include <iostream>
#include <vector>
#include <algorithm>

int main(){
    std::vector<float> v;
    v.push_back(1.0);
    v.push_back(1.0);
    v.push_back(3.5);
    v.push_back(3.5);

    struct approx_equal
    {
        bool operator()(float l, float r)
        {
            return std::abs(l - r) < 0.01;
        }
    };
    approx_equal f;

    std::unique(v.begin(), v.end(),f);
}

Вот ошибка, которую он выдал:

testUnique.cpp: In function 'int main()':
testUnique.cpp:21:37: error: no matching function for call to 'unique(std::vector<float>::iterator, std::vector<float>::iterator, main()::approx_equal&)'
   21 |     std::unique(v.begin(), v.end(),f);
      |                                     ^
In file included from C:/msys64/mingw64/include/c++/9.2.0/algorithm:62,
                 from testUnique.cpp:3:
C:/msys64/mingw64/include/c++/9.2.0/bits/stl_algo.h:995:5: note: candidate: 'template<class _FIter> _FIter std::unique(_FIter, _FIter)'
  995 |     unique(_ForwardIterator __first, _ForwardIterator __last)
      |     ^~~~~~
C:/msys64/mingw64/include/c++/9.2.0/bits/stl_algo.h:995:5: note:   template argument deduction/substitution failed:
testUnique.cpp:21:37: note:   candidate expects 2 arguments, 3 provided
   21 |     std::unique(v.begin(), v.end(),f);
      |                                     ^
In file included from C:/msys64/mingw64/include/c++/9.2.0/algorithm:62,
                 from testUnique.cpp:3:
C:/msys64/mingw64/include/c++/9.2.0/bits/stl_algo.h:1025:5: note: candidate: 'template<class _FIter, class _BinaryPredicate> _FIter std::unique(_FIter, _FIter, _BinaryPredicate)'
 1025 |     unique(_ForwardIterator __first, _ForwardIterator __last,
      |     ^~~~~~
C:/msys64/mingw64/include/c++/9.2.0/bits/stl_algo.h:1025:5: note:   template argument deduction/substitution failed:
testUnique.cpp: In substitution of 'template<class _FIter, class _BinaryPredicate> _FIter std::unique(_FIter, _FIter, _BinaryPredicate) [with _FIter = __gnu_cxx::__normal_iterator<float*, std::vector<float> >; _BinaryPredicate = main()::approx_equal]':
testUnique.cpp:21:37:   required from here
testUnique.cpp:21:37: error: template argument for 'template<class _FIter, class _BinaryPredicate> _FIter std::unique(_FIter, _FIter, _BinaryPredicate)' uses local type 'main()::approx_equal'
   21 |     std::unique(v.begin(), v.end(),f);
      |                                     ^
testUnique.cpp:21:37: error:   trying to instantiate 'template<class _FIter, class _BinaryPredicate> _FIter std::unique(_FIter, _FIter, _BinaryPredicate)'

А вот мой набор флагов:

g++ -c -g -O3 -Wp,-D_FORTIFY_SOURCE=2 -m64 -Wshadow -Wall -DMX_COMPAT_32 -fexceptions -fno-omit-frame-pointer -D__WIN32__ -std=c++03 testUnique.cpp -o testUnique.o

Ответы [ 2 ]

5 голосов
/ 05 ноября 2019

Я думаю, что Лямбда, возможно, уже существовала,

Нет. Лямбды были введены в C ++ 11.

... и функторы / функциональные объекты существовали, верно?

Функторы - это просто объекты с operator(), поэтому они всегда были там (хотя и не уверены,когда термин "функтор" был фактически введен для них).

Для правильной формальной формулировки я отсылаю вас к другим ссылкам, небрежно говоря это

auto f = [](float l, float r){ 
  return std::abs(l - r) < 0.01; 
};
f(0.1,0.2);

Это эквивалентно

struct unnamed {
    bool operator()(float l, float r) {
        return std::abs(l - r) < 0.01; 
    }
};
unnamed f;
f(0.1,0.2);

Т.е. вы всегда можете заменитьлямбда с классом рукописных функторов. Создайте экземпляр функтора и передайте его вместо лямбды.

Полный пример:

#include <iostream>
#include <vector>
#include <algorithm>

struct approx_equal{
    bool operator()(float l, float r) {
        return std::abs(l - r) < 0.01; 
    }
};

int main(){
    std::vector<float> v{1.0, 1.0, 3.5, 3.5 };

    approx_equal f;

    v.erase(std::unique(v.begin(), v.end(),f),v.end());

    // sorry this is c++11, replace with iterator loop to see output pre-c++11
    for (const auto& x : v) std::cout << x << " ";  
}

PS: В C ++ 03 вы не можете определить класс функтора локально, а затем использовать егов качестве параметра шаблона (обратите внимание, что вы явно не передаете его как параметр шаблона, но unique должен определить его тип из передаваемого вами параметра).

2 голосов
/ 05 ноября 2019

Лямбды не существуют в C ++ 03, они были введены в C ++ 11.

Поскольку ваш лямбда-пример не нуждается в захвате значений, вы можете заменить его простой автономной функцией,вам не нужен функтор, например:

#include <iostream>
#include <vector>
#include <algorithm>

bool approx_equal(float l, float r) {
    return std::abs(l - r) < 0.01;
}

int main(){
    std::vector<float> v;
    v.push_back(1.0);
    v.push_back(1.0);
    v.push_back(3.5);
    v.push_back(3.5);

    std::unique(v.begin(), v.end(), approx_equal);
}

Однако вы также можете использовать функтор. Пытаясь использовать функтор, вы просто определили тип функтора внутри самого main(), сделав его локальным, на что пожаловался компилятор. Вместо этого определите тип функтора в глобальной области видимости (вы все равно можете использовать локальную переменную для создания экземпляра типа), например:

#include <iostream>
#include <vector>
#include <algorithm>

struct approx_equal {
    bool operator()(float l, float r) {
        return std::abs(l - r) < 0.01;
    }
};

int main(){
    std::vector<float> v;
    v.push_back(1.0);
    v.push_back(1.0);
    v.push_back(3.5);
    v.push_back(3.5);

    approx_equal f;
    std::unique(v.begin(), v.end(), f);

    // or:
    // std::unique(v.begin(), v.end(), approx_equal{});
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...