Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::is_arithmetic returns false for int type inside generic lambda: Undefined behavior?

Consider:

#include <iostream>
#include <typeinfo>
#include <type_traits>

#include <cxxabi.h>

#include <boost/hana.hpp>
namespace hana = boost::hana;

struct Person {
  BOOST_HANA_DEFINE_STRUCT(Person,
    (std::string, name),
    (int, age)
  );
};

template<typename T>
void stringify(const T& v) {
    hana::for_each(hana::accessors<T>(), [&v](auto a) {
        // Here I'm printing the demangled type, just to make sure it is actually the type I'm thinking it is.
        std::cout << abi::__cxa_demangle(typeid(decltype(hana::second(a)(v)){}).name(), 0, 0, 0);

        // If the value is arithmetic, "quote" should be an empty string. Else, it should be an actual quote.
        // UNEXPECTED BEHAVIOR IS HERE
        std::string quote{(std::is_arithmetic<decltype(hana::second(a)(v))>::value?"":"\"")};

        // Finally do what we're here for.
        std::cout << " " << hana::first(a).c_str() << " = " << quote << hana::second(a)(v) << quote << "\n";
    });
}

int main() {
    Person john;
    john.name = "John Doe";
    john.age = 42;
    stringify(john);
}

See it live

Output:

std::__cxx11::basic_string</*...*/> name = "John Doe"
int age = "42"

I'm trying to use std::is_arithmetic to tell if I'm dealing with a number instead of some other non-arithmetic type, and print (or not) a quote accordingly.

But for some reason, the value being "returned" (through ::value member) is false, even though I'm passing an int(I make sure I'm doing that right by first printing the demangled type using gcc's cxxabi.h)

As you can see from the output, this causes the int to be printed with quotes.

My question(s) is: why is it returning false? Does this have anything to do with the generic lambda? Can I fix it?

I'm actually testing this directly on Coliru, so you can assume whatever gcc version used there (Currently 6.3.0).

like image 868
Cássio Renan Avatar asked Sep 16 '26 00:09

Cássio Renan


1 Answers

Your problem is that in spite of the type typeid returns (int) your actual type inside the lambda is int const& and is_arithmetic is not specialized for that exact type. You can get the type you actually want with std::decay or a combination of std::remove_const and std::remove_reference.

like image 80
2 revsllonesmiz Avatar answered Sep 17 '26 15:09

2 revsllonesmiz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!