Here is one more solution.
#onclude <iostream>
#include <format>
#include <limits>
#include <concept>
#include <stdexcept>
template <std::integral R = int, std::integral ...Bits>
constexpr R to_integral( Bits ... bits )
{
if constexpr (std::numeric_limits<R>::digits < sizeof... ( bits ))
{
throw std::invalid_argument( "The number of arguments exceeds the number of bits in the result type." );
}
else
{
R result = 0;
if constexpr (sizeof...( bits ) != 0)
{
size_t i = sizeof...( bits );
( result |= ... |= ( static_cast< R >( !!bits ) << --i ) );
}
return result;
}
}
static_assert( to_integral( 1, 1, 0, 1, 0, 1 ) == 0b101011 );
int main()
{
std::cout << std::format( "{:#b}\n", to_integral<int>() );
std::cout << std::format( "{:#b}\n", to_integral( 1, 1, 0, 1, 0, 1 ) );
std::cout << std::format( "{:#b}\n", to_integral<unsigned long long>( 1, 1, 0, 1, 0, 1 ) );
}
The program output is
0b0
0b101011
0b101011
The solution is based on two fundamental concepts of the C++ Standard.
The first one is the binary left fold expression. According to the C++ Standard (the C++23 Standard, section "13.7.4 Variadic templates"):
10 The instantiation of a fold-expression (7.5.6) produces:
(10.3) — ( (((E op E1) op E2) op · · · ) op EN ) for a binary left fold, and
And the second one is relative to the assignment and compound assignment operator. According to the C++ Standard (the C++23 Standard, section "7.6.19 Assignment and compound assignment operators"):
1 The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand; their result is an lvalue of the type of the left operand, referring to the left operand. The result in all cases is a bit-field if the left operand is a bit-field. In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. The right operand is sequenced before the left operand. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation.
If you need to build a binary representation in the descending order then just make only two minor changes. They are
size_t i = 0;
( result |= ... |= ( static_cast< R >( !!bits ) << i++ ) );
std::initializer_list<bool>seems more appropriate.{}for calling the function, shouldn't it ?{}would be requiredstd::from_chars, but it's still a bit involved to use: godbolt.org/z/G7vsbx3qK