How to cast an arbitrary std::integral type to unsigned?

154 Views Asked by At

I am trying to cast an std::integral type to unsigned when a special flag is set i.e. it should simply be interpreted as an unsigned number in this case. This cast is necessary in that case, because the number needs to be passed as an unsigned to another function not controlled by me later on. However, I can't find a solution that compiles successfully.

Here's a MWE with the most promising solution (which I took from https://stackoverflow.com/a/33049554):

#include <concepts>
#include <type_traits>
#include <iostream>

bool change = true;

void do_something(const std::floating_point auto num) {
    // Do something else
    std::cout << "Got floating num: " << num;
    return;
}

void do_something(const std::integral auto num) {
    if (change) {
        // Interpret as unsigned
        std::make_unsigned<decltype(num)>::type unsigned_num = num; // FAILS
        std::cout << "Got integral and changed to unsigned: " << unsigned_num;
    } else {
        // Do something else
        std::cout << "Got integral and keeping as is: " << num;
        return;
    }
}

int main() {
    do_something(1);
    do_something(-1);
    do_something(0.5);

    change = false;
    do_something(1);
    do_something(-1);
    do_something(0.5);
}

(compile with g++ --std=c++20)

Compiler Error Message:

mwe.cc:7:30: error: ‘floating_point’ in namespace ‘std’ does not name a type; did you mean ‘is_floating_point’?
    7 | void do_something(const std::floating_point auto num) {
      |                              ^~~~~~~~~~~~~~
      |                              is_floating_point
mwe.cc:7:45: error: expected ‘,’ or ‘...’ before ‘auto’
    7 | void do_something(const std::floating_point auto num) {
      |                                             ^~~~
mwe.cc: In function ‘void do_something(int)’:
mwe.cc:9:46: error: ‘num’ was not declared in this scope; did you mean ‘enum’?
    9 |         std::cout << "Got floating num: " << num;
      |                                              ^~~
      |                                              enum
mwe.cc: At global scope:
mwe.cc:13:30: error: ‘integral’ in namespace ‘std’ does not name a type; did you mean ‘internal’?
   13 | void do_something(const std::integral auto num) {
      |                              ^~~~~~~~
      |                              internal
mwe.cc:13:39: error: expected ‘,’ or ‘...’ before ‘auto’
   13 | void do_something(const std::integral auto num) {
      |                                       ^~~~
mwe.cc:13:6: error: redefinition of ‘void do_something(int)’
   13 | void do_something(const std::integral auto num) {
      |      ^~~~~~~~~~~~
mwe.cc:7:6: note: ‘void do_something(int)’ previously defined here
    7 | void do_something(const std::floating_point auto num) {
      |      ^~~~~~~~~~~~
mwe.cc: In function ‘void do_something(int)’:
mwe.cc:16:45: error: ‘num’ was not declared in this scope; did you mean ‘enum’?
   16 |                 std::make_unsigned<decltype(num)>::type unsigned_num = num;
      |                                             ^~~
      |                                             enum
mwe.cc:16:49: error: template argument 1 is invalid
   16 |                 std::make_unsigned<decltype(num)>::type unsigned_num = num;
      |                                                 ^
mwe.cc:16:57: error: expected initializer before ‘unsigned_num’
   16 |                 std::make_unsigned<decltype(num)>::type unsigned_num = num;
      |                                                         ^~~~~~~~~~~~
mwe.cc:17:74: error: ‘unsigned_num’ was not declared in this scope; did you mean ‘unsigned’?
   17 |                 std::cout << "Got integral and changed to unsigned: " << unsigned_num;
      |                                                                          ^~~~~~~~~~~~
      |                                                                          unsigned
mwe.cc:20:68: error: ‘num’ was not declared in this scope; did you mean ‘enum’?
   20 |                 std::cout << "Got integral and keeping as is: " << num;
      |                                                                    ^~~
      |                                                                    enum

What is causing these issues and how would you suggest to overcome them?

1

There are 1 best solutions below

0
gera verbun On

According to the documentation you should do as in the example here: make_unsigned

That is, for your example:

using unsigned_num_t = std::make_unsigned_t<decltype(num)>;
const unsigned_num_t unsigned_num = num;

Or as you were told, you should only add typename, like this:

typename std::make_unsigned<decltype(num)>::type unsigned_num = num;