简体   繁体   中英

How to call std::unique with custom predicate in C++03?

I saw this example of how to do it in C++11:

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

However, this fails for me in 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)>'

How can I do this in C++03? I think Lambdas may have already existed, and functors/function objects existed, right? Just looking for a simple solution, does not need to be extendable - it will only ever be used here.

Here is an example of code which will not compile for me:

#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);
}

Here's the error it produced:

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)'

And here was my set of flags:

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

I think Lambdas may have already existed,

No. Lambdas have been introduced in C++11.

... and functors/function objects existed, right?

Functors are simply objects with an operator() , so they always have been there (though not sure when the term "functor" was actually introduced for them).

For the formal correct way to put it I refer you to other references, sloppy speaking this

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

Is equivalent to

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

Ie you can always replace a lambda with a handwritten functor class. Create an instance of the functor and pass that instead of the lambda.

Complete example:

#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: In C++03 you cannot define the functor class locally and then use it as template parameter (note you do not explicitly pass it as template parameter, but unique has to deduce its type from the parameter you pass in).

Lambdas don't exist in C++03, they were introduced in C++11.

Since your lambda example does not need to capture values, you can replace it with a simple standalone function, you don't need a functor, eg:

#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);
}

However, you can use a functor, too. In your attempt to use a functor, you simply defined the functor type inside of main() itself, making it a local type, which the compiler complained about. Define the functor type in global scope instead (you can still use a local variable to instantiate the type), eg:

#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{});
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM