3

I am wishful here, but I want to be precise about the question. I want to improve implementation of detecting member templates by their names alone, but I came across an obstacle. I can't find any way to detect overloaded static/non-static member functions. Very important part of this question is, that I can't use this trick, because it detects any name (I'm already using it in current implementation, kinda useful), and I can't specify the types, because that misses the point of using names alone.

For reference, see my other question. I posted current has_member_template_bar implementation as an answer there. I don't think I should post all of it in this question.

The question stays the same - Can we detect overloaded member functions, without specifying their arguments, or using mentioned trick? I know I'm maybe asking for impossible, but it never hurts to ask.

Community
  • 1
  • 1
xinaiz
  • 7,744
  • 6
  • 34
  • 78

1 Answers1

1

The question stays the same - Can we detect overloaded member functions, without specifying their arguments, or using mentioned trick? I know I'm maybe asking for impossible, but it never hurts to ask

Actually, it is not impossible.
It follows a minimal, working example:

template<typename T, typename R, typename... A>
void proto(R(T::*)(A...));

template<typename, typename = void>
constexpr bool has_single_f = false;

template<typename T>
constexpr bool has_single_f<T, decltype(proto(&T::f))> = true;

struct S {
    void f(int) {}
    void f(char) {}
};

struct U {
    void f() {}
};

int main() {
    static_assert(not has_single_f<S>, "!");
    static_assert(has_single_f<U>, "!");
}

Of course, you need to add more stuff to distinguish between member methods and data members, but it's trivial to add them (see the header type_traits) and I tried to keep the example as minimal as possible.

The basic idea is that the call to proto fails if the given function is overloaded, for it's an ambiguous call.
Anyway, the error is discarded because of SFINAE rules.
Arguments are not required to be specified as requested.
Note also that proto does not require to be defined, but it's important that its return type is void. Otherwise you have to slightly modify the call to decltype as it follows:

template<typename T>
constexpr bool has_single_f<T, decltype(proto(&T::f), void())> = true;

As you can see from the example code, the static_asserts verify that f is overloaded in S and it is not in U.


The example above is based on template variables, that are part of the language since C++14.
If you prefer the well known struct based solution that works with C++11, you can use the following detector:

#include<type_traits>

//...

template<typename, typename = void>
struct has_single_f: std::false_type {};

template<typename T>
struct has_single_f<T, decltype(proto(&T::f))>: std::true_type {};

//...

int main() {
    static_assert(not has_single_f<S>::value, "!");
    static_assert(has_single_f<U>::value, "!");
}
skypjack
  • 49,335
  • 19
  • 95
  • 187