HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Template Method Checker

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
templatecheckermethod

Problem

I have written some template helpers to check if a class has a certain method with a certain signature. The code is based on this answer. I attempted to extend it for generic methods. An important feature is that it also detects inherited methods.

```
#include
#include
#include

template
struct has_method {
static_assert(std::integral_constant::value,
"Third template parameter needs to be of function type.");
};

template
struct has_method {
private:
template
static constexpr auto check(T *) ->
typename std::is_same().template call(
std::declval()...)),
Ret>::type
{
return typename std::is_same().template call(
std::declval()...)),
Ret>::type();
//return to surpresswarnings
}

template
static constexpr std::false_type check(...)
{
return std::false_type();
};

typedef decltype(check(0)) type;

public:
static constexpr bool value = type::value;
};
struct existent_caller {
template
constexpr auto call(Args... args) const
-> decltype(std::declval().existent(args...))
{
return decltype(std::declval().existent(args...))();
//return to surpresswarnings
}
};
struct nonexsistent_caller {
template
constexpr auto call(Args... args) const
-> decltype(std::declval().nonexsistent(args...));
};
struct X {
int existent(const std::string &) { return 42; }
};

struct Y : X {
};

struct Z {
};
int main(int argc, const char *argv[])
{
static_assert(
has_method::value,
"Should have existent method");
static_assert(
has_method::value,
"Should have existent method");
static_assert(
!has_method::value,
"Should not have existent method");
static_assert(
!has_method::value,
"Should not have nonexistent method");
static_assert(
!has_method::value,
"Sho

Solution

Compiler warnings

I compiled your code with -Wall -Wextra -pedantic and they managed to trigger some warnings:

-
You have an extra comma at the end of the function static constexpr std::false_type check(...). Get rid of it.

-
You're not using argc nor argv. You might want to simply use int main() if you're not going to use the parameters.


Always request more warnings, never ignore them.
-- Morwenn, 2015-06-11


That quote was totally unoriginal.
-- Morwenn, same day

Other miscellaneous stuff

There isn't much to say, so I will only nitpick as I usually do :)

-
You don't need the methods check to have a definition since you only use them for their signature. Remove their body and let them undefined, it will make it clearer why they exist. This also holds for existent_caller<>::call.

Alternatively, you can use the list initialization syntax instead if not providing the body triggers some warnings so that you don't have to repeat the return type:

static constexpr auto check(T *) ->
    typename std::is_same().template call(
                              std::declval()...)),
                          Ret>::type
{
    // Default-construct an instance of the return type
    return {};
}


-
typedef is a bit old-fashioned and subjectively not that much readable. You could use the new type alias with using instead:

using type = decltype(check(0));


-
By the way, check takes a pointer, make it clear by passing nullptr instead of 0:

using type = decltype(check(nullptr));


-
Your methods in existentcaller and nonexistentcaller could be static. It seems that you don't need them to be regular methods.

-
Also, you don't need to return 0; at the end of main. If the compiler reaches the end of main without finding a return statement, it automagically return 0. Removing return 0; is a way to document that your program can't return anything else than 0 from and that it should never return error codes.

Code Snippets

static constexpr auto check(T *) ->
    typename std::is_same<decltype(std::declval<caller>().template call<T>(
                              std::declval<Args>()...)),
                          Ret>::type
{
    // Default-construct an instance of the return type
    return {};
}
using type = decltype(check<C>(0));
using type = decltype(check<C>(nullptr));

Context

StackExchange Code Review Q#92993, answer score: 2

Revisions (0)

No revisions yet.