2

There is a std::find_first_of but no std::find_last_of. I want to make such a template function by myself. I consulted this code Is there a function like find_last_of in std but not in string?

But this function was compiled failed. The error seems strange, cannot convert from _FwdIt1 to _FwdIt1. They are the same type. My compiler is visual studio 2017.

template<class _FwdIt1, class _FwdIt2>
        inline _FwdIt1 find_last_of(const _FwdIt1 _First1, const _FwdIt1 _Last1,
            const _FwdIt2 _First2, const _FwdIt2 _Last2)
    {
        return find_first_of(reverse_iterator(_Last1), reverse_iterator(_First1), _First2, _Last2); //error C2440: 'return': cannot convert from '_FwdIt1' to '_FwdIt1'
    }


    void test()
    {
        const char* s = "0123456789";
        char* sb = "54";
        cout<<find_last_of(s, s + strlen(s), sb, sb+strlen(sb));
    }
Administrator
  • 254
  • 1
  • 8
  • Is that the *complete* and *full* error message you get? No informational notes? Nothing else *at all*? There should be some more output which should give some hints about the problem. – Some programmer dude Nov 01 '18 at 08:05
  • Also (but unrelated to your problem), note that symbols starting with an underscore and followed by an upper-case letter (like e.g. `_FwdIt1` or `_FwdIt2`) are reserved in all scopes, and that you should not use such symbol names your self. See [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) for more information. – Some programmer dude Nov 01 '18 at 08:07
  • 2
    An quick and maybe dirty way to fix this is to use `auto` as a return type. – Petok Lorand Nov 01 '18 at 08:11
  • To expand on previous comment. You have probably copied the style from the implementation of `first_first_of` on your platform. The point is that `std::find_first_of` is part of the implementation of C++. As such, it may only use symbols that are reserved to the implementation. If it used a symbol like `FwdIt1`, that would be broken by `#define FwdIt1 42` in your code - so they use `_FwdIt1` because you aren't allowed to write `#define _FwdIt1 42`. Contrary-wise, the implementation is fully entitled to write '#define _FwdIt1 42` (or something much more esoteric) and break your code. – Martin Bonner supports Monica Nov 01 '18 at 08:15
  • @Someprogrammerdude, I renamed _FwdIt1 to MyFwdIt1. Then the error message changed somehow. Error C2440 'return': cannot convert from '_FwdIt1' to 'MyFwdIt1' – Administrator Nov 01 '18 at 08:17
  • @Lorand, yes, haha, it worked! – Administrator Nov 01 '18 at 08:21
  • What compiler are you using? All the compilers on godbolt are complaining they want a template argument for std::reverse_iterator. – Martin Bonner supports Monica Nov 01 '18 at 08:22
  • @MartinBonner, oh I forgot to mention the compiler. I use visual studio 2017 – Administrator Nov 01 '18 at 08:24
  • That was one of the compilers I tried on Godbolt. Please show a [mcve]. – Martin Bonner supports Monica Nov 01 '18 at 08:27

2 Answers2

3

If you are passing ::std::reverse_iterator as first two parameters of ::std::find_first_of then result will be ::std::reverse_iterator as well and to get original iterator from it you need to use .base() method:

return _FwdIt1
{
    find_first_of
    (
         reverse_iterator(_Last1)
    ,    reverse_iterator(_First1)
    ,    _First2
    ,    _Last2
    )
    .base()
};

online compiler

user7860670
  • 35,849
  • 4
  • 58
  • 84
2

I followed @Lorand's suggestion. changed the return type to auto, it worked.

    template<class MyFwdIt1,
        class _FwdIt2>
        inline auto find_last_of(const MyFwdIt1 _First1, const MyFwdIt1 _Last1,
            const _FwdIt2 _First2, const _FwdIt2 _Last2)
    {
        return std::find_first_of(reverse_iterator(_Last1), reverse_iterator(_First1), _First2, _Last2);
    }

    void test()
    {
        const char* s = "0123456789";
        char* sb = "54";
        auto it = find_last_of(s, s + strlen(s), sb, sb+strlen(sb));
        cout << it - reverse_iterator(s + strlen(s)) << endl;
    }
Administrator
  • 254
  • 1
  • 8
  • 1
    It works, but according to @VTT what you are returning from the function is a reverse iterator, so you should keep that in mind if you want to incerement/decrement it. – Petok Lorand Nov 01 '18 at 08:29
  • 1
    Yes, this was before @VTT's answer come out. Now I use VTT's solution. :) – Administrator Nov 01 '18 at 08:31