This is my C++ code:
inline static void swap(std::string& a1, std::string& a2) {
std::string temp( std::move(a1));
a1 = std::move( a2 );
a2 = std::move( temp );
}
I ran this function 1000000 times and it took 78ms on average, but the std one just took 13ms. I just looked at the implementation of std::swap, I found it just the the same as mine, so why is mine so slow?
According to the standard §21.3.2.8/p1 swap [string.special] (Emphasis Mine):
template<class charT, class traits, class Allocator>
void swap(basic_string<charT, traits, Allocator>& lhs,
basic_string<charT, traits, Allocator>& rhs)
noexcept(noexcept(lhs.swap(rhs)));
1 Effects: Equivalent to: lhs.swap(rhs);
Consequently, std::swap specializes/has an overload for std::string and is equivalent as calling the member function std::basic_string::swap.
A possible implementation would be:
template<class Elem, class Traits, class Alloc>
inline
void
swap(std::basic_string<Elem, Traits, Alloc>& left,
std::basic_string<Elem, Traits, Alloc>& right) noexcept(noexcept(left.swap(right))) {
left.swap(right);
}
As for why your implementation is slower, my guess is that even if you move the one string to the another, the destructor for the temporary string will still be called. Something that is not the case in the STL compatible implementation above.
Related
I don't understand why this code compiles and runs:
std::string s;
std::cin >> s;
// if (s == "done") { // version 1
if ("done" == s) { // version 2
std::cout << "We're done here" << std::endl;
}
Version 1 works as I would expect. The compiler sees that s is a std::string, and uses the std::string definition of == to do the comparison.
However, when comparing a variable to an explicit value, I like to use the trick of putting the explicit value first in case one day I accidentally use = instead and do an assignment instead. Hence, version 2.
Now version 2 works on my compiler (llvm on MacOS) the same way as version 1, but I'm not sure why (or if it's a reliable result). I would have though that the compiler sees "done" as a char* explicit value (literal) and says, "hey, == makes no sense on char*" and give me a compilation error message. But my compiler doesn't do that, it compiles without complaint and the code executes the same way as version 1.
What am I misunderstanding here?
The type of "done" is not char*. It is const char[5].
But in any case, it works because if you include <string>, which you must have to use std::string, then (before C++20) you include an overload for operator== of the form
template< class CharT, class Traits, class Alloc >
bool operator==( const std::basic_string<CharT,Traits,Alloc>& lhs,
const CharT* rhs );
and one of the form
template< class CharT, class Traits, class Alloc >
bool operator==( const CharT* lhs,
const std::basic_string<CharT,Traits,Alloc>& rhs );
See https://en.cppreference.com/w/cpp/string/basic_string/operator_cmp for reference.
std::string is just std::basic_string with CharT being char and Traits and Alloc being some defaults that don't matter here.
So effectively one overload accepts a const std::string& as left-hand argument and const char* as right-hand argument, and the other accepts the reverse.
const char[N] can be deduced as const char* and it is implicitly convertible to the latter for every N, so the first overload is viable for s == "done" and the second for "done" == s.
The standard library is written with these overloads specifically so that your use will work. Your approach of using the "done" == s variant makes sense, because "done" = s would indeed be an error. operator= can only be overloaded with a class type on the left-hand side.
Since C++20, the overloads look a bit different. In particular it isn't necessary to have both anymore. The compiler now automatically tries overloads matching the rewritten expression with reversed operands of == when doing overload resolution.
to an explicit value,
explicit constant
I am not sure what you mean here, but "explicit value" and "explicit constant" are not standard terminology. Probably you mean "(string) literal" instead.
and says, "hey, == makes no sense on char*"
It doesn't work that way. As soon as either side of == is a class type, the compiler has to consider that == may be overloaded to match the expression.
For the class template std::basic_string the equality operator == is overloaded in particular the following way
template<class charT, class traits, class Allocator>
bool operator==(const charT* lhs, const basic_string<charT, traits, Allocator>& rhs);
So the first argument maybe a C string literal without requiring any conversion (except the standard implicit conversion from an array type to pointer to the array element type).
Actually the operator has three overloads
template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT, traits, Allocator>& lhs,
const basic_string<charT, traits, Allocator>& rhs) noexcept;
template<class charT, class traits, class Allocator>
bool operator==(const charT* lhs, const basic_string<charT, traits, Allocator>& rhs);
and
template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT, traits, Allocator>& lhs,
const charT* rhs);
A quote from the standard regarding std::basic_string_view equality comparison operators (see http://eel.is/c++draft/string.view#comparison):
[Example 1: A sample conforming implementation for operator== would be:
template<class charT, class traits>
constexpr bool operator==(basic_string_view<charT, traits> lhs,
basic_string_view<charT, traits> rhs) noexcept {
return lhs.compare(rhs) == 0;
}
template<class charT, class traits>
constexpr bool operator==(basic_string_view<charT, traits> lhs,
type_identity_t<basic_string_view<charT, traits>> rhs) noexcept {
return lhs.compare(rhs) == 0;
}
— end example]
Won't the second comparison operator be sufficient for all use cases? If the answer is no please provide the example code that will stop working (or will work differently) if the first comparison operator is removed. If the answer is yes then why does the C++ standard explicitly require the first operator to be defined?
I think this is insufficient reduction as a result of the adoption of <=> in P1614. Before that paper, there were three ==s in the example:
template<class charT, class traits>
constexpr bool operator==(basic_string_view<charT, traits> lhs,
basic_string_view<charT, traits> rhs) noexcept {
return lhs.compare(rhs) == 0;
}
template<class charT, class traits>
constexpr bool operator==(basic_string_view<charT, traits> lhs,
type_identity_t<basic_string_view<charT, traits>> rhs) noexcept {
return lhs.compare(rhs) == 0;
}
template<class charT, class traits>
constexpr bool operator==(type_identity_t<basic_string_view<charT, traits>> lhs,
basic_string_view<charT, traits> rhs) noexcept {
return lhs.compare(rhs) == 0;
}
At the time, we needed three operators. The type_identity ones handle stuff like sv == literal and literal == sv, and then you need the homogeneous one to disambiguate sv == sv.
With the <=> adoption (or, more precisely, the == changes from P1185), == becomes symmetric so you don't need both type_identity operators to handle literal == sv, just the one suffices. I was basically mechanically going through and dropping unnecessary == and != overloads, so I removed that second.
But what I did not realize is with the other one gone, we now no longer need the homogeneous comparison to disambiguate from the other two (we don't have other two anymore, just other one) - it's enough to just have the one type_identity overload.
You could open an editorial issue to remove the homogeneous one. Or not, it's just an example anyway.
I have a simple map std::map<string, my_namespace::MyType>, I am using c++11 so I replaced it with unordered_map for performance reasons. I got the following error when comparing an iterator with end().
auto cit = str_map_.find(str);
if (cit != str_map_.end()) {
...
}
In instantiation of 'bool my_namespace::operator!=(const T1&, const T2&) [with T1 = std::__detail::_Node_iterator<std::pair<const std::__cxx11::basic_string, my_namespace::MyType, false, true>; T2 = std::__detail::_Node_iterator<std::pair\ <const std::__cxx11::basic_string, my_namespace::MyType, false, true>]': no matching function ...
I debugged it down to my rather creative comparison operators for my_namespace::MyType:
template <class T>
struct MyType {
T* mt_;
};
struct MyTempClass {
std::string mtc_;
static int Compare(MyType<MyTempClass> const& lhs, MyType<MyTempClass> const& rhs) {
return lhs.mt_->mtc_.compare(rhs.mt_->mtc_);
}
static int Compare(std::string const& lhs, MyType<MyTempClass> const& rhs) {
return lhs.compare(rhs.mt_->mtc_);
}
static int Compare(MyType<MyTempClass> const& lhs, std::string const& rhs) {
return lhs.mt_->mtc_.compare(rhs);
}
};
template <class T1, class T2>
bool operator !=(T1 const& lhs, T2 const& rhs) {
int res = MyTempClass::Compare(lhs, rhs);
return (res != 0);
}
template <class T1, class T2>
bool operator ==(T1 const& lhs, T2 const& rhs) {
int res = MyTempClass::Compare(lhs, rhs);
return (res != 0);
}
static std::unordered_map<std::string, MyType<MyTempClass>> my_map;
But I am still puzzled why it did happen: the same code works fine with a plain map, and values type should not be involved in iterator comparisons?
You defined an operator!= overload that takes any type as an argument. That overload is in the same namespace as the type MyType. Therefore, it can potentially be found via ADL.
As the error message indicates, the std::unordered_map iterator used by the standard library is a class template specialization, specialized on the std::unordered_map template arguments. As such, when you compare iterators with !=, ADL is performed on the arguments and the namespaces searched by ADL also include the namespaces of type template arguments of the types of the arguments. Therefore, your operator!= overload in the namespace of MyType will also be found and participate in overload resolution.
Assuming you are using libstdc++ as standard library implementation based on the error message, you can have a look at it's implementation of the operator!= for hash table iterators and you will see that it uses a base class for these iterators, and defines the comparison operators for references to the base class objects.
As a consequence, the standard overload for the iterator comparison requires a derived-to-base reference conversion in its arguments, while your overload does not.
Therefore your overload is better and will be chosen to do the cit != str_map_.end() comparison. Your overload tries to pass the arguments MyTempClass::Compare which clearly doesn't work, because these functions don't expect std::unordered_map iterators.
The solution is not to overload operators for pairs of types that do not depend on user-defined types. Restrict your overloads to your own types:
template <class T1, class T2>
bool operator !=(MyType<T1> const& lhs, T2 const& rhs) {
int res = MyTempClass::Compare(lhs, rhs);
return (res != 0);
}
template <class T1, class T2>
bool operator !=(T1 const& lhs, MyType<T2> const& rhs) {
int res = MyTempClass::Compare(lhs, rhs);
return (res != 0);
}
(equivalently for operator==).
As far as I know, it is not forbidden to overload the operators for standard library type pairs, but I also don't think that the standard library is required to account for conflicts this generates as in your code.
With std::map the standard library implementation might have chosen a different way of implementing the iterator comparison, which made it a better fit in overload resolution or avoided that ADL finds your overload by not making the iterator a template specialized on the key/value type.
I've got a data object that I'm trying to get all of the operators working with. It's one chunk of data with variable ptrs into it, and has any number of different types and sizes and whatnot. Types are handled with enums and templates and switch statements. So for each x, d[x] is one type, with any number of them and they can be vectors. so d[x][y] and d[x][y][z]. I made an internal helper object to help with this. So I have [] overloaded to do things like this, and it'll return the correct type fine: (gcc 4.6.1)
[Edit: I have the same trouble with d(x,y,z)--the problem isn't the [] operator]
int i = d[0][3][5];
I'm overloading T() in this helper object.
template <class T>
data::helper::operator T (); // switch(x)...return different types
data::helper data::operator [] (int i); // recurse, return helper(t, d, x, i, j);
So I'll just return this object, which resolves it's type at that point (switch with cases tied to t->get< char>(d, x, i, j), etc.). So the problem is, if I want to do anything like this
int i = d[0][1] + d[4][2];
if (d[5][1] != d[3][0]) ...
then I ended up having to overload every operator to take in this temporary array helper object. And now I'm running into having to make a temporary value in there sometimes for some of the operators, which is a pain.
Basically, I feel like I need the operator T() to resolve first, before the compiler tries to take two of these and add them.
I have to do this anyway for the = and +=, etc. operators, but I'd like to delete these jazillion macros helping me define all of these other operators.
Also, I feel like if I could overload the lvalue operator somehow, I could not worry about the = operator. Maybe that and &() (which right now just returns a templated ptr). ...? Or actually, this is more what I mean, at least for d[] = something, but I haven't got this to work. I'm not sure how to convert a ptr of any type to this return value.
data::helper & data::operator [] (int i);
I have most of this working but it's a lot of code, and I think I'm going to have to add an extra if statement to every access to do the temp stuff, which I don't want to do. So what did I miss?
Edit: using d(x,i,j) is the same as d[x][i][j]. I'm pretty sure I'm doing at least the beginning part of what's being used in the link n.m. posted. The problem is resolving that last helper object into its data before it's used in a statement. Somehow the compiler wants an operator that accepts the helper object even though it knows how to resolve it when it's alone... I think. Been a couple days into overloading every operator so I forget all the details. :)
But the main problem now is with stuff like this:
helper operator + (helper & l, helper & r)
I would like to define the following but it's not getting used--then I think my problems might be solved. similar story for unary ops ~, -, and postfix ++, --.
template <class T> T operator + (helper & l, helper & r)
But all of this is just because there's something off about my T(), I think. Most of this is new to me, so I bet I'm missing something.
The practical way to do this kind of thing is with expression templates.
I'd change your return values from operator[] to an expression template even.
This will use C++11 features, because it makes it shorter.
enum class ExpressionType { Index, Addition };
template< ExpressionType Op, typename LHS, typename RHS >
struct Expression {
LHS lhs;
RHS rhs;
template<typename T>
operator T();
};
// to separate out the evaluation code:
template< typename T, ExpressionType Op, typename LHS, typename RHS >
struct Evaluate {
T operator()( Expression<Op, LHS, RHS> exp ) const;
};
template< ExpressionType Op, typename LHS, typename RHS >
template<typename T>
Expression<Op,LHS,RHS>::operator T() {
return Evaluate<T,Op,LHS,RHS>()( std::move(*this) );
}
// further specializations needed:
template< typename T, typename RHS >
struct Evaluate< T, ExpressionType::Index, data, RHS > {
T operator()( Expression<Op, ExpressionType::Index, data, RHS> exp ) const {
// we just assume RHS can be treated like an integer. If it cannot,
// we fail to compile. We can improve this with SFINAE elsewhere...
return exp.lhs.get_nth(exp.rhs);
}
};
template< typename T, typename LHS, typename RHS >
struct Evaluate< T, ExpressionType::Addition, LHS, RHS > {
T operator()( Expression<Op, ExpressionType::Index, data, RHS> exp ) const {
// code with all of LHS, RHS and T visible!
}
};
template<typename E>
struct is_expression : std::false_type {};
template<ExpressionType Op, typename LHS, typename RHS>
struct is_expression<Expression<Op,LHS,RHS> : std::true_type {};
template<ExpressionType Op, typename LHS, typename RHS>
Expression<Op, LHS, RHS> make_expression( LHS&& lhs, RHS&& rhs ) {
return { std::forward<LHS>(lhs), std::forward<RHS>(rhs) };
}
// here is why I want to start out with returning an expression. This SFINAE test
// is extremely easy because of that -- we overload operator+ on any two types, so long
// as one of them is an Expression!
template<typename LHS, typename RHS, typename=typename std::enable_if<is_expression<LHS>::value || is_expression<RHS>::value >::type>
ExpressionType<ExpressionType::Addition, LHS, RHS> operator+( LHS&& lhs, RHS&& rhs )
{
return make_expression<ExpressionType::Addition>(std::forward<LHS>(lhs), std::forward<RHS>(rhs) );
}
so the idea is, we build at compile time a tree of templates that represent the order in which various expressions are evaluated by the compiler.
When we finally cast it to a concrete type T, only then do we start the evaluation work.
This avoids having to create any temporaries, but does mean we have to do a lot of template mojo in order to get things up and running. The above is a sketch of such an template expression tree generator.
To see a complete implementation of a simple case, here is a link to wikipedia's article on the subject, where a full blown expression tree system is built up to do std::vector vector processing without temporaries.
From wikipedia:
// A class template to express an equality comparison interface.
template<typename T> class equal_comparable
{
friend bool operator==(T const &a, T const &b) { return a.equal_to(b); }
friend bool operator!=(T const &a, T const &b) { return !a.equal_to(b); }
};
class value_type
// Class value_type wants to have == and !=, so it derives from
// equal_comparable with itself as argument (which is the CRTP).
: private equal_comparable<value_type>
{
public:
bool equal_to(value_type const& rhs) const; // to be defined
};
This is supposed to be the Barton-Nackman, that could achieve compile-time dimensional analysis (checking if some operations applied to variables end up in comparable numbers, like speed comparable to space/time but no acceleration).
Could anyone explain me how, or at least explain me what are the NON-TEMPLATE members?
Thanks
The rules of the language have changed since the pattern was invented, although care was taken not to break it. In other words, as far as I can tell, it still works but for different reasons than it originally did. I don't think I would base an attempt at dimensional analysis on this pattern as I think there are better ways of doing that today.
I also think the example is too trivial to be helpful. As already stated the instantiation of equal_comparable<value_type> causes operator== and operator!= for value_type to appear. Since they are non-members it doesn't matter that the inheritance is private, they're still eligable for selection when resolving a call. It's just hard to see the point in this example. Let's say however, that you add a template parameter to equal_comparable and a few other things:
template<typename U, typename V> class equal_comparable
{
friend bool operator==(U const &a, V const &b) { return a.equal_to(b); }
friend bool operator!=(U const &a, V const &b) { return !a.equal_to(b); }
};
class some_other_type
{
bool equal_to(value_type const& rhs) const;
};
class value_type
: private equal_comparable<value_type>, // value_type comparable to itself
private equal_comparable<some_other_type> // value_type comparable to some_other_type
{
public:
bool equal_to(value_type const& rhs) const;
bool equal_to(some_other_type const& rhs) const;
};
Disclaimer: I have no idea if this is the way it's supposed to be used but I'm reasonably sure that it would work as described.
These are actually nontemplate nonmembers - the comparison operators in the base template - they get used by the ADL for the derived class. A template member would be something like:
class C
{
...
template < typename T > void DoGreatStuff( T t ) { ... }
...
};
The instantiation of equal_comparable<value_type> in value_type class causes the compiler to generate two comparison functions:
friend bool operator==(value_type const &a, value_type const &b) { return a.equal_to(b); }
friend bool operator!=(value_type const &a, value_type const &b) { return !a.equal_to(b); }
These functions are nontemplate since they do not depend on any template parameter, but they are also nonmembers since they are declared as friend.