patterncppMinor
Template Method Checker
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
```
#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
-
You have an extra comma at the end of the function
-
You're not using
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
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:
-
-
By the way,
-
Your methods in
-
Also, you don't need to
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.