fakedrake
fakedrake

Reputation: 6856

C++ type name as a literal string for error report in static_assert

I am using this macro to make sure some types line up:

#define TYPE_EQ(t1, t2) static_assert(std::is_same<t1, t2>::value)

Bear with my contrived example:

#include <iostream>

#define TYPE_EQ(t1, t2) static_assert(std::is_same<t1, t2>::value)

class Fn1 {
 public:
    int operator()(const char s) {
        return s == 'a' ? 0 : 1;
    }
    typedef char Domain;
    typedef int Codomain;
};

class Fn2 {
 public:
    char operator()(const bool s) {
        return s ? 'a' : 'b';
    }
    typedef bool Domain;
    typedef char Codomain;
};

template<typename F1, typename F2>
class Compose {
 public:
    Compose () {
        TYPE_EQ(typename F1::Domain, typename F2::Codomain);
    }

    typedef typename F1::Codomain Codomain;
    typedef typename F2::Domain Domain;

    Codomain operator()(const Domain& x) {
        F1 f1;
        F2 f2;
        return f1(f2(x));
    }
};

int main() {
    std::cout << Compose<Fn2, Fn1>()(true) << std::endl;
    return 0;
}

Here I get simply error: static_assert failed, but I would like to know what the type mismatch is. For that I think I would need a string representation of the types at compile time so for example I could have:

#define TYPE_EQ(t1, t2) static_assert(std::is_same<t1, t2>::value, \
                                      type_str(t1) " != " type_str(t2))

Edit: I didn't think compilers would disaggree on this. I don't have gcc ATM but clang sais:

g++ -Wall -std=c++17 test.cc -o test && ./test
test.cc:27:9: error: static_assert failed
        TYPE_EQ(typename F1::Domain, typename F2::Codomain);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cc:3:25: note: expanded from macro 'TYPE_EQ'
#define TYPE_EQ(t1, t2) static_assert(std::is_same<t1, t2>::value)
                        ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cc:41:18: note: in instantiation of member function 'Compose<Fn2, Fn1>::Compose'
      requested here
    std::cout << Compose<Fn2, Fn1>()(true) << std::endl;
                 ^
1 error generated.

To clarify the real problem is much more complex so I want the final types, ie int and boo, not typenames.

Upvotes: 2

Views: 738

Answers (1)

Jarod42
Jarod42

Reputation: 217970

Classical way to retrieve type for debugging is to use incomplete type:

template <typename> struct Debug;

Debug<Fn1::Domain> d;

Produces error similar to:

error: aggregate 'Debug<char> d' has incomplete type and cannot be defined
Debug<Fn1::Domain> d;

Upvotes: 1

Related Questions