Tag Archives: ACCU

Using std::tie to implement operator< (by Anthony Williams at ACCU 2013)

I’ve used std::tie to unbind the underlying data from a std::tuple in the past:

auto t = std::make_tuple( 1, 42, 100 );
int a, b, c;
std::tie( a, b, c ) = t;

But I hadn’t seen this handy trick for using std::tie to implement operator<

#include <tuple>

struct S
{
  S(int a_, int b_, int c_) : a(a_), b(b_), c(c_)
  {}

  int a;
  int b;
  int c;
};

bool operator<( const S& lhs, const S& rhs )
{
  return std::tie( lhs.a, lhs.b, lhs.c )
       < std::tie( rhs.a, rhs.b, rhs.c );
}

int main()
{
  S s1( 1, 2, 3), s2 ( 1, 2, 4 ), s3 ( 0, 2, 3);

  std::cout << "s1 should be less than s2: " << (s1 < s2) << "\n"
            << "s3 should be less than s1: " << (s3 < s1) << "\n";

  return 0;
}

Notice that std::tie does not copy the variables (as per the earlier example, it takes them by reference). You can also mimic the use of use of underscore in F#

let f i = (i, i*2, i*4)
let a, _, c = f 5

using std::ignore

auto f = []( int i){ return std::tuple(i, i*2, i*4); }
int a, b;
std::tie( a, std::ignore, b ) = f( 5 );

5 Comments

Filed under C++ Code

Examples of SFINAE (by Jonathan Wakely at ACCU 2013)

I’m currently attending ACCU2013 at Bristol and saw Jonathan Wakely’s presentation on SFINAE (Substitution Failure Is Not An Error) this morning.

This is a traditional SFINAE example using type traits.  true_type and false_type just need to have different sizes, then we can use function template specialization to differentiate between two cases.

typedef char true_type;
typedef double false_type;
template<class T>
true_type is_iter( typename T::iterator_category* t );
template<class T>
false_type is_iter(...);
template<class T>
struct is_iterator
{
  static const bool value =
    (sizeof(is_iter<T>(0)) == sizeof(true_type));
};

void testTypeTrait()
{
 std::cout
    << "Try int " << is_iterator<int>::value << "\n";
    << "Try vector<int>::iterator "
    << is_iterator<std::vector<int>::iterator>::value << "\n";
}

This example later in the presentation really stood out – a step towards Concepts, it shows syntax available today for restricting the types that will compile with a given template (thanks to C++11 aliasing and default arguments for template parameters):

class WidgetBase
{};

class Widget : public WidgetBase
{};

class Bodget
{};

class Decorator
{
private:
template<class T>
using IsDerivedWidget = typename std::enable_if<
        std::is_base_of<WidgetBase, T>::value>::type;

public:
template<class T,
class Requires = IsDerivedWidget<T>>
Decorator( const T& )
{}
};

So if I instantiate Decorator with Widget, it compiles (because Widget derives from WidgetBase), but instantiating with Bodget yields a compiler error (because Bodget does not inherit from WidgetBase).

Widget w;
Decorator decoratedWidget( w );
Bodget b;
Decorator decoratedBodget( b ); // Error

This code all compiles with recent versions of gcc (e.g. 4.7).  Under Visual Studio, only the traditional example compiles (default arguments for function templates are not yet supported, neither is aliasing, not even with the Nov ’12 CTP).

1 Comment

Filed under C++ Code

Implementing operator<() for strict weak ordering

Overload113Cover
The latest edition of Overload Magazine (a publication by the ACCU) includes a recipe for implementing operator<, as is often required when you want store some class in an STL associative container.

bool operator<( const T& rhs ) const
{
if ( a != rhs.a ) return a < rhs.a;
if ( b != rhs.b) return b < rhs.b;
...
return false;
}

This assumes that operator!= exists on that class and in my view muddies the waters between equivalence (the property you test in a std::set or std::map with operator<) and equality (the test in std::vector or std::list with operator==). Of course, if operator== exists, you can easily amend the recipe accordingly, but again neither operator== nor operator!= have default implementations so may not be provided.

Where necessary, you can fall back onto this more verbose recipe:

bool operator <(const T& rhs) const
{
  if ( a < rhs.a )
    return true;
  else if (rhs.a < a)
    return false;

  if ( b < rhs.b)
    return true;
  else if (rhs.b < b)
    return false;

  // repeat for all child elements c, d, e etc
  return false;
}

Leave a comment

Filed under C++ Code