0

I have a template class which accepts a tuple of pairs of a type and an integral constant (some of the types can be repeated so it can't be a hana::map). I'm looking to iterate over the tuple and call a static toString() type method defined for each type. The error I am receiving is:

"error: type 'decltype(hana::first(c))' (aka 'boost::hana::type_impl::_ &') cannot be used prior to '::' because it has no members"

struct A
{
    static std::string toString() {return std::string("A");}
};
struct B
{
    static std::string toString() {return std::string("B");}
};

using namespace hana::literals;
std::array<std::string,3> ret;
constexpr auto tupleOfPairs = hana::make_tuple(
    hana::make_pair(hana::type_c<A>, 0_c),
    hana::make_pair(hana::type_c<B>, 0_c),
    hana::make_pair(hana::type_c<B>, 5_c));

size_t idx = 0;
hana::for_each(tupleOfPairs, [&](auto c)
{
    ret[idx++] = decltype(hana::first(c))::type::toString();
});

I had something very similar working when it was just a tuple (using decltype(c)::type::toString()) but as soon as I made the tuple elements pairs with an integral constant I can't seem to extract the type of the first element of the pair and do the same.

Thanks

RyanP
  • 1,898
  • 15
  • 20

1 Answers1

0

TL;DNR: That decltype yields a type "reference to ...", which (it's a reference) obviously has no members. Simple fix: remove the reference with std::remove_reference:

ret[idx++] = 
  std::remove_reference_t<decltype(hana::first(c))>::type::toString();

This is not about hana. Taking it "out of the loop" we can reduce your case further to

#include <string>
struct A {
  static std::string toString() {
    return std::string("A");
  }
};
template<typename T> T & get_it() {
  static T thing;
  return thing;
}
int main() {
  std::string str = decltype(get_it<A>())::toString();
}

This gives (basically) the same error message as yours:

error: 'decltype(get_it())' (aka 'A &') is not a class, namespace, or enumeration

This is telling us that A & (a reference to A) is not a class (etc.) and can thus not have a (static) member. The same is true when your compiler tells you that:

error: type 'decltype(hana::first(c))' (aka 'boost::hana::type_impl::_ &') cannot be used prior to '::' because it has no members

boost::hana::type_impl::_ & is a reference. Of course it has no members. The referenced class has, so just remove the reference with std::remove_reference.

The fact that the return type of first is reference type is also noted in the documentation, btw (emphasis mine):

Returns the first element of a pair.Note that if the Product actually stores the elements it contains, hana::first is required to return a lvalue reference, a lvalue reference to const or a rvalue reference to the first element, where the type of reference must match that of the pair passed to first. If [.., not applicable here].

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63