Cools stuff I’m not gonna use

Heh, wanted to just do a simple string match — nothing fancy even, just has to test for an exact match in a small set of strings...

There’re all kinds of ways to do this simply. But I wanted pretty.

  if (std::vector { "one", "two", "three" } --> some_string)

That is, of course, not as cool as my <x_in_xs> stuff:

  if (some_string in { "one", "two", "three" })

but x-in-xs requires a whole lot of template meta-programming and (probably) some bloat... (I should probably test that)


But the pretty is also several hundred bytes more in size than a simple:

  if (is_any_of( some_string, "one", "two", "three" ))

...which is all I need, just a couple places in the code.

Interestingly, that also compiles to the same size if I write something abominable like:

  if (std::string( "one\0two\0three", 13 ).find( some_string ) != std::string::npos)

which also unfortunately returns true for the empty string...


“Wut? Only several hundred bytes?” you say?

Yes. My program is going to be as tiny as possible without resorting to excessive hand mico-optimizing. Just going to avoid constructs that I don’t need. (For example, I use a number of std::unordered_map in the code. No sense in adding several thousand bytes worth of code for a std::unordered_set when a map will stand-in nicely.)


Also, in case you were curious:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// if (std::vector { "one", "two", "three" } --> some_string)

#include <algorithm>

template <typename XS>
struct container_ref
{
  const XS & xs;
  container_ref( const XS & xs ) : xs{xs} { }
		
  template <typename X>
  bool operator > ( const X & x ) const 
  {
    using std::begin;
    using std::end;
    auto iterator = std::find( begin(xs), end(xs), x );
    return iterator != end(xs);
  }
};

template <typename XS>
container_ref <XS>
operator -- ( const XS & xs, int )
{
  return container_ref( xs );
}

1
2
3
4
5
6
7
8
9
10
11
12
13
// if (is_any_of( some_string, "one", "two", "three" ))

template <typename X>
bool is_any_of( const X & )
{
  return false;
}

template <typename X, typename X0, typename...XS>
bool is_any_of( const X & x, const X0 & x0, XS...xs )
{
  return (x == x0) or is_any_of( x, xs... );
}

Sorry, not gonna post the x-in-xs stuff today. Like I said — lots of boilerplate template meta-programming.

Oh, and, C++17. Don’t give me grief about C++27.


Ever get your brain in a whirl over stupid stuff like this?
but x-in-xs requires a whole lot of template meta-programming and (probably) some bloat... (I should probably test that)

Ok, I'm curious. I've got this working in five lines (all the metaprogramming is in the standard library):
static_assert(2u in initializer_list<int>{0, 1, 2, 3}); // <-- C++20
But I can't figure out how you got rid of the initializer_list<int>. If I delete it, clang helpfully complains that a list just can't appear there, like it's forbidden by the language grammar.

If I do a trick to make it work, this blows up instead:
static_assert(some_string in some_range);
I'm out of ideas. Any hints?

Sorry, not gonna post the x-in-xs stuff today.

Hmm. Tomorrow then? :-)
Last edited on
You can’t get rid of the initializer list excesses. The C++ Standard restricts them to use with constructors and assignment operators. Doing anything else incurs -Wparentheses warnings, at minimum.

The workaround is (2 in_{0, 1, 2, 3}). Aaannnd you can guess how that works, lol. (It’s actually worse than you think, but cleaner code, at least.)


Maybe someday I’ll put my (very small) libduthomhas library on github. It includes the Radical Language Modification stuff.

The x-in-xs started out as a fun exercise answering a question here:
https://stackoverflow.com/a/36020725/2706707

I’ve improved it since, but it now requires the following type-traits testing objects:

  • has_count
  • is_comparable
  • is_iterable

In total that’s about 220 LOC (not counting comments/documentation) just for C++11 / C++14 / C++17 SFINAE type-traits testing stuff (and implementing the “in” membership stuff).

EDIT: By the way, you cheated! I’m still clinging to my C++17 man!

The reason I’m hesitant is that I think I goobered it a while ago and haven’t touched it since.


Give me a couple of days to look it over and I’ll post my RLM stuff, I guess.

Bonus: I’ll also post how to loop over arbitrarily-many lists in parallel, like:

1
2
3
4
5
6
7
8
  for (auto [x, y, z] : xs, ys, zs)  
    ...

  for (auto [x, y] : xs, ys, defaults)
    ...

  for (auto [x, y, z] : xs, defaults(ys), zs)
    ...

It’s basically an overflow-safe zip-iterator — something I find über useful. (The “defaults” version supplies default values for lists that run out early. Otherwise the iteration stops at the shortest list. The last example shows both behaviors: stop at the shorter of xs or zs, but supply default values for ys.)


In all cases there are limitations. RLM tries to do uncomfortable things to C++.

But Oh So Spiffy Things.
Last edited on
So, I’m looking over my old code and tweaking it to put up for all the world to see.

As it currently stands, having the “defaults” keyword (object) is currently opt-in.

1
2
#include <duthomhas/for>
using duthomhas::defaults;

(Or even just using namespace duthomhas;)

After that you can write things like:

1
2
3
4
5
6
7
int ns[] = { 1, 2, 3, 4, 5, 6, 7 };
const char * ths[] = { "st", "nd", "rd" };

for (auto [n, th] : defaults, ns, ths)
{
  std::cout << n << (th ? th : "th") << "\n";
}
or even
1
2
3
4
5
6
7
int ns[] = { 1, 2, 3, 4, 5, 6, 7 };
const char * ths[] = { "st", "nd", "rd" };

for (auto [n, th] : ns, defaults(ths,"th"))
{
  std::cout << n << th << "\n";
}


Is that reasonable?
Or should I make it opt-out instead?

1
2
#define NO_DUTHOMHAS_FOR_DEFAULTS
#include <duthomhas/for> 

(Either way you could still get at it by specifying full namespace: for (... : ..., duthomhas::defaults), but that is clunky at best.)

It isn’t unreasonable to make it opt-out. For example, boost::logical::tribool automatically creates the “indeterminate” object in the global scope.

I’m not sure what people would tend to prefer. So:


What do you prefer?
(And, more importantly, why?)
Last edited on
Registered users can post here. Sign in or register to post.