Random Useful Stuff Thread

Pages: 12
range + iterator --> ranger

1
2
3
4
5
6
7
8
9
#include <utility>

template <typename Iterator>
struct ranger : public std::pair <Iterator, Iterator>
{
  ranger( Iterator begin, Iterator end = Iterator() ) : std::pair <Iterator, Iterator> { begin, end } { }
  Iterator begin() { return this->first;  }
  Iterator end  () { return this->second; }
};

regex + ranger --> re_ranger

11
12
13
14
15
16
17
18
19
20
21
#include <regex>
#include <string>

struct re_ranger : public std::regex, public ranger <std::sregex_iterator>
{
  template <typename RegEx>
  re_ranger( const RegEx& re, const std::string& s )
  : std::regex( re )
  , ranger( std::sregex_iterator( s.begin(), s.end(), *this ) )
  { }
};

Fancy-pants example:

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <iterator>
#include <sstream>

int main()
{
  const std::string s = "The quick brown fox jumps over the lazy dog.";
  
  std::cout << "stringstream ranger:\n";
  std::istringstream iss( s );
  for (auto word : ranger( std::istream_iterator <std::string> ( iss ) )) 
  {
    std::cout << "  " << word << "\n";
  }
  
  std::cout << "\n" "regex re_ranger:\n";
  for (auto word : re_ranger( "[^\\s]+", s ))
  {
    std::cout << "  " << word.str() << "\n";
  }
}
stringstream ranger:
  The
  quick
  brown
  fox
  jumps
  over
  the
  lazy
  dog.

regex re_ranger:
  The
  quick
  brown
  fox
  jumps
  over
  the
  lazy
  dog.
Oh yeah, almost forgot, I use this one all the time: RValue --> LValue

 
template <typename T> T& lvalue( T&& arg ) { return arg; }

Remember, folks, that doing this means doing an end-run around C++’s safety checks and treating a temporary object as if it were not. Don’t use it outside of contexts where the temporary is guaranteed to exist.

Example: Simple word count program. Takes input from either a list of files or from standard input.

1
2
3
4
5
6
7
8
9
10
unsigned word_count( std::istream& );

int main( int argc, char** argv )
{
  unsigned sum = 0;
  if (argc > 1) while (argc --> 1) sum += word_count( lvalue( std::ifstream( argv[argc] ) ) );
  else                             sum  = word_count( std::cin );

  std::cout << sum << "\n";
}

Enjoy!
Duthomhas wrote:
Oh yeah, almost forgot, I use this one all the time: RValue --> LValue


Hi,

We already have this:

https://en.cppreference.com/w/cpp/types/remove_reference

Which looks like it does the same thing (returning the underlying value), unless I am mistaken :+) I mean: a rvlaue is a rvlaue reference isn't it?

Thanks for all the good stuff you are posting, and your great comments :+)
The return value of std::remove_reference() can't be passed to a function expecting a T &, only a const T & or a T &&.
Another thing it might be useful for could be
 
lvalue(Foo(...)) = bar;
Here, Foo might open a life and the assignment might serialize bar and save it.
This is a simple function that I use for input validation, to make sure the user doesn't enter a letter when he should enter a number. It's kind of hackish, but it works. I use it because I'm a nut about this sort of thing.

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
double cinCheck ()
{
	double amount;
	bool loopEnd;
	
	do
	{
		cin >> amount;
		
		if (cin.fail())
		{
			cout << "Error. Entry must be a number. \n: ";
			cin.clear();
			cin.ignore(INT_MAX, '\n');
			
			loopEnd = false;
		}
		else
		{
			loopEnd = true;
		}
	}while(!loopEnd);
	
	return amount;
}

The bool and such is mainly because I don't like saying while(true) or while(1). And that's because I might make a mistake, and then it goes infinite.

[Edit]
seeplus wrote:
Perhaps some admin (?) would mark this thread as 'sticky' so that it stays at/near the top of the forum.

Not much chance, unfortunately. The admin hasn't been seen since 1997, when he was sucked into his compiler and became a Java program.
Last edited on
helios wrote:
The return value of std::remove_reference() can't be passed to a function expecting a T &, only a const T & or a T &&.


Right :+)

There is also std::add_lvalue_reference, std::add_rvalue_reference as well as the other stuff in traits, like const-volatility specifiers et al. So one can wrangle the type specifier any which way.
Make sure that the stream exception mask is set so that your software does not attempt to recover from an irrecoverable problem forever.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
double cinCheck2()
{
  std::cin.exceptions(std::ios::badbit | std::ios::eofbit); 
	
  double amount;
  while (true)
  {
    if(std::cin >> amount) 
      return amount; 
    std::clog << "expected number\n";
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 
  }
}


The return value of std::remove_reference() can't be passed to a function expecting a T&
remove_reference is a class template that computes a type, so it would need to be used with a conversion of some kind

Maybe something like this (tricky, and perhaps not even entirely correct)
static_cast<typename std::remove_reference<decltype((expression))>::type&>(expression)
The "extra" parentheses are required around expression

Or perhaps, (even more tricky)
static_cast<decltype((expression))&>(expression)

The lvalue function may be useful with iterator adapters, for example when constructing regex_token_iterator.

Last edited on
...for example when constructing regex_token_iterator.

That is exactly when you cannot use it, as the regex temporary is cleaned up and the iterator lives on with only bad memories.

Also, my re_ranger takes care of that problem. :O)
Last edited on
It can be used as long as one understands lifetime rules. For example
parse(regex_token_iterator{text_begin, text_end, lvalue(std::regex{"."})}, regex_token_iterator{});

Note that declaring an extra variable is a small price to pay to eliminate avoidable and subtle lifetime bugs.
Last edited on
Convert an enumerator of a scoped enumeration (an enum class) to its underlying type
1
2
3
4
#include <type_traits>
template <auto E> requires std::is_enum_v<decltype(E)>
  inline constexpr auto underlying_value 
    = static_cast<std::underlying_type_t<decltype(E)>>(E);

Demo:
https://godbolt.org/z/75sY34xf4

Extract unsigned integers from a byte stream with known endianness:
Up-to-date mainstream compilers understand this idiom and generate byte swap instructions if appropriate

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
27
28
29
30
31
32
33
34
[[nodiscard]] inline constexpr u16 extract_u16_le(u8 const* p) noexcept
{ return (p[0] << 0) | (p[1] << 8); }
[[nodiscard]] inline constexpr u32 extract_u32_le(u8 const* p) noexcept
{ return (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); }
[[nodiscard]] inline constexpr u16 extract_u16_be(u8 const* p) noexcept
{ return (p[0] << 8) | (p[1] << 0); }
[[nodiscard]] inline constexpr u32 extract_u32_be(u8 const* p) noexcept
{ return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); }


inline constexpr void insert_u16_le(u8* p, u16 n) noexcept
{
  p[0] = (n & 0x00ff) >> 0;
  p[1] = (n & 0xff00) >> 8;
}
inline constexpr void insert_u32_le(u8* p, u32 n) noexcept
{
  p[0] = (n & 0x000000ff) >> 0;
  p[1] = (n & 0x0000ff00) >> 8;
  p[2] = (n & 0x00ff0000) >> 16;
  p[3] = (n & 0xff000000) >> 24;
}
inline constexpr void insert_u16_be(u8* p, u16 n) noexcept
{
  p[0] = (n & 0xff00) >> 8;
  p[1] = (n & 0x00ff) >> 0;
}
inline constexpr void insert_u32_be(u8* p, u32 n) noexcept
{
  p[0] = (n & 0xff000000) >> 24;
  p[1] = (n & 0x00ff0000) >> 16;
  p[2] = (n & 0x0000ff00) >> 8;
  p[3] = (n & 0x000000ff) >> 0;
}

Demo:
https://godbolt.org/z/5rT7vvcMb

Last edited on
Topic archived. No new replies allowed.
Pages: 12