Can you detect template member of a class using std::is_detected

I use std::experimental::is_detected to determine if class has certain member functions:

#include <utility>
#include <experimental/type_traits>

template<typename USC>
class Descriptor
{
private:

    template<class T>
    using has_member1_t = 
        decltype(std::declval<T>().member1(std::declval<std::vector<char> &>()));

public:

    static constexpr bool has_member1 = 
        std::experimental::is_detected_convertible_v<long long,
                                                     has_member1_t,
                                                     USC>;
};

The problem is I also need to determine if class has certain template member function with following signature:

template<typename Derived>
int member2(Eigen::ArrayBase<Derived> &&)

I’ve tried to do it like so:

//Inside Descriptor

template<class T, class U>
using has_member2_t = 
    decltype(std::declval<T>().member2(std::declval<Eigen::ArrayBase<U> &&>()));

static constexpr bool has_member2 = 
    std::experimental::is_detected_convertible_v<long long,
                                                 has_member2_t,
                                                 USC>;

but it doesn’t work. As I’m not really experienced with C++ TMP I would like to know is there a way to achieve this with std::experimental::is_detected or some other utility?

>Solution :

If c++20 is an option, this kind of code has been made a lot easier to both read and write by using concepts.

#include <iostream>
#include <vector>

struct Foo {
    int member1(int) {
        return 1;
    }

    template <typename T>
    double member2(std::vector<T>) {
        return 2.5;
    }
};

struct Bar {};

template <typename T>
concept MyConcept = requires (T t) {
    { t.member1(0) } -> std::same_as<int>;              // We can check return type
    { t.template member2<int>(std::vector<int>{}) };    // but we don't have to
};

int main() {
    static_assert(MyConcept<Foo>);
    static_assert(!MyConcept<Bar>);
}

The issue with your attempt is that you are not passing anything as U for the check. I would also modify it to use the .template member2<...> syntax to explicitly check for a template.

Here is an example of that.

#include <iostream>
#include <vector>
#include <utility>
#include <experimental/type_traits>

struct Foo {
    int member1(int) {
        return 1;
    }

    template <typename T>
    double member2(std::vector<T>) {
        return 2.5;
    }
};

struct Bar {};

template<class T, class U>
using has_member2_t = 
    decltype(std::declval<T>().template member2<U>(std::declval<std::vector<U> &&>()));

int main() {
    static constexpr bool has_member2_Foo = 
    std::experimental::is_detected_convertible_v<long long,
                                                 has_member2_t,
                                                 Foo, double>;

    static constexpr bool has_member2_Bar = 
    std::experimental::is_detected_convertible_v<long long,
                                                 has_member2_t,
                                                 Bar, double>;

    static_assert(has_member2_Foo);
    static_assert(!has_member2_Bar);
}

Leave a Reply