1

For learning purposes and to understand how things work, I'm trying to rewrite this without templates, in the case wstring:

#include <ctype.h>

template<typename charT>
struct my_equal 
{
    bool operator()(charT ch1, charT ch2) { return toupper(ch1) == ch2; }
};

template<typename T>
bool contains(const T& str1, const T& str2)
{
    typename T::const_iterator it = std::search(str1.begin(), str1.end(), str2.begin(), str2.end(), my_equal<typename T::value_type>());
    return (it != str1.end());    
}

I'm trying this:

struct my_equal 
{
    bool operator()(wchar_t ch1, wchar_t ch2) { return toupper(ch1) == ch2; }
};

bool contains(const wstring str1, const wstring str2)
{
    wstring::const_iterator it = std::search(str1.begin(), str1.end(), str2.begin(), str2.end(), my_equal());
    return (it != str1.end());
}

It works but it's twice or three times slower when benchmarking it. Why?

Is there something wrong in the "translation without templates"?

Also, is it possible to avoid using a struct but having the my_equal comparison directly in search(...)?

Basj
  • 41,386
  • 99
  • 383
  • 673
  • 1
    Can you show how you benchmarked this? They should in theory produce the exact same assembly. – NathanOliver Jul 11 '17 at 12:01
  • @NathanOliver: will be difficult to show here, because it's part of a big application. Is `const T&` => `const wstring` correct? (what about the `&`?) Idem for `typename T::const_iterator` => `wstring::const_iterator`? `charT` => `wchar_t`? – Basj Jul 11 '17 at 12:02
  • 11
    Your non-template version likely makes a copy of the strings, whereas the template passes them as `const &` – peterchen Jul 11 '17 at 12:04
  • 1
    @peterchen Good spot. I missed that. That will kill performance. – NathanOliver Jul 11 '17 at 12:04
  • How to correct it @peterchen? – Basj Jul 11 '17 at 12:05
  • 3
    `const T& => const wstring&` – NathanOliver Jul 11 '17 at 12:05
  • 1
    `bool contains(const wstring & str1, const wstring & str2)` - see e.g. here: https://stackoverflow.com/questions/373419/whats-the-difference-between-passing-by-reference-vs-passing-by-value – peterchen Jul 11 '17 at 12:06
  • Ok that's the answer (if you want to copy/paste it as an answer!), thanks! – Basj Jul 11 '17 at 12:08
  • Last thing @NathanOliver and peterchen: can I avoid the `struct` and have a version with `search(..., my_eval_here_without_struct())` ? – Basj Jul 11 '17 at 12:09
  • @Basj You can use a function but you can get better performance with a functor. With C++11/14 I would just use a lambda to make an anonymous functor. – NathanOliver Jul 11 '17 at 12:12
  • @NathanOliver do you mean this: `[](wchar_t ch1, wchar_t ch2) { return toupper(ch1) == ch2; }`? – Basj Jul 11 '17 at 12:19
  • @Basj Yes. That is a lambda. – NathanOliver Jul 11 '17 at 12:23
  • I don't know whether to vote for closure as caused by a simple typographic error or a duplicate of the question explaining by-value vs by-reference. – underscore_d Jul 11 '17 at 12:25
  • Thanks @NathanOliver. I don't see much speed improvement, it even seems that it could be a little slower with this lambda instead of struct. Is there another way to make such a functor? – Basj Jul 11 '17 at 12:28
  • Nope. You make a named class type or a lambda. – NathanOliver Jul 11 '17 at 12:34

1 Answers1

2

You omitted some ampersands. Make it,

bool contains(const wstring &str1, const wstring &str2)
{
    wstring::const_iterator it = std::search(str1.begin(), str1.end(), str2.begin(), str2.end(), my_equal());
    return (it != str1.end());
}
Jive Dadson
  • 16,680
  • 9
  • 52
  • 65