1

I would like to find out if a type defines a member function with a template argument but the template argument is constrained with SFINAE.

Example I have a type A with a single function foo

struct A{
   template<typename T>
   std::enable_if<Condition<T>,ReturnType> foo(T t){ ... }
};

Condition is some condition e.g. std::is_pos_v

Right now I'm using boost::hana::is_valid to figure out if a type has a member function like foo() or foo(int) but when with template argument I'm lost.

I would like to write something like this

auto has_foo = hana::is_valid([](auto t) -> delctype(hana::traits::declval(t).foo(???)){});
has_foo(hana::type_c<A>); // <-- I want this to return true

The question is what should I put instead of ??? ?


It is probably impossible for the compiler to "prove" that a type A satisfy: "For every type T which satisfy Condition there is a member function A::foo(T)"

So to make it easier for the compiler, I would be happy to at least "prove" that for a type A holds: "There is a type T such that there is a member function A::foo(T)"

Unfortunately, this is still hard in my example because this would require proving that there is a type which satisfy Condition.

Thus isn't it possible for the purpose of introspection to ignore SFIANE? Then I could pick an arbitrary type and test existence of e.g. A::foo(int).

tom
  • 1,520
  • 1
  • 12
  • 26
  • This sounds impossible. Moreover, what if that type is a particular not-yet-instantiated class template ? – llllllllll Apr 10 '18 at 14:20
  • And why you want this high-order logic ? What's the actual problem you want to solve ? – llllllllll Apr 10 '18 at 14:22
  • @liliscent Yeah it is probably impossible. Anyway, I'm playing around with C++ and trying to implement basic notions from category theory, such as different kind of categories, functors, products, sum, exponential objects etc. So the code is really generic and I would like to catch errors as soon as possible, otherwise the error messages will be unreadable. Thus the described problem IS the problem I'm trying to solve. – tom Apr 10 '18 at 14:35
  • Or maybe I can rephrase it a little bit. I want to make sure that a given function object(struct `A`) is really a map from some set(given by `Condition`). (For me a set is a collection of values of type `T` and the type satisfies `Condition`) – tom Apr 10 '18 at 14:37
  • Perhaps post your `is_valid` code. I don't see why that wouldn't work unless I misunderstand the question. – Jason Rice Apr 10 '18 at 15:32
  • 1
    @JasonRice I have added a code I would like to write. – tom Apr 10 '18 at 16:41

1 Answers1

2

As stated, there is no facility provided for this kind of introspection short of writing a compiler plugin and walking the AST yourself.

You can certainly use hana::is_valid if you provide a concrete T to make a complete and valid expression.

I provided an additional example that allows providing a "concept" assuming some kind of facility for providing a concrete T for whatever "concept" you put in. This is a bit of a reach though.

#include <boost/hana.hpp>
#include <type_traits>
#include <utility>

namespace hana = boost::hana;
using hana::Sequence;


struct A {
    template <typename T>
    std::enable_if_t<Sequence<T>::value, void> foo(T) { }
};

struct B {
    template <typename T>
    void bar(T) { }
};


template <typename T>
auto has_foo_1 = hana::is_valid([](auto&& a)
    -> decltype(std::forward<decltype(a)>(a).foo(std::declval<T>())) { });


template <template <typename, typename> typename Concept>
auto declval_concept_impl = int{};

template <>
auto declval_concept_impl<Sequence> = hana::tuple<>{};

template <template <typename, typename> typename Concept>
using declval_concept = std::add_rvalue_reference_t<decltype(declval_concept_impl<Concept>)>;

template <template <typename, typename> typename Concept>
auto has_foo_2 = hana::is_valid([](auto&& a)
    -> decltype(std::forward<decltype(a)>(a).foo(declval_concept<Concept>{})) { });

int main() {
    A a;
    B b;

    static_assert(    has_foo_1<hana::tuple<>>(a));
    static_assert(not has_foo_1<hana::tuple<>>(b));
    static_assert(    has_foo_2<Sequence>(a));
    static_assert(not has_foo_2<Sequence>(b));
}
Jason Rice
  • 1,686
  • 1
  • 12
  • 17
  • 1
    If I understand it correctly then by "some kind of facility for providing a concrete `T`" you mean the line `auto declval_concept_impl = hana::tuple<>{};` right? Which is in this example a little bit silly but I think I can see the potential. – tom Apr 10 '18 at 23:28
  • Yes, I think the tooling option sounds realistic. – Jason Rice Apr 11 '18 at 00:39