Random Useful Stuff Thread

Pages: 12
Sep 29, 2021 at 3:15am
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.
Sep 29, 2021 at 3:32am
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!
Sep 29, 2021 at 5:23am
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 :+)
Sep 29, 2021 at 12:06pm
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.
Sep 29, 2021 at 11:36pm
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 Sep 29, 2021 at 11:39pm
Sep 30, 2021 at 1:18am
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.
Sep 30, 2021 at 1:24am
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'); 
  }
}


Sep 30, 2021 at 1:47am
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 Sep 30, 2021 at 1:50am
Sep 30, 2021 at 3:36am
...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 Sep 30, 2021 at 3:37am
Sep 30, 2021 at 6:15am
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 Sep 30, 2021 at 6:17am
Oct 4, 2021 at 11:46am
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 Oct 4, 2021 at 11:56am
Topic archived. No new replies allowed.
Pages: 12