Skip to content

Instantly share code, notes, and snippets.

@Denisss025
Last active March 1, 2016 07:06
Show Gist options
  • Save Denisss025/03e37b82188b0ca15ca6 to your computer and use it in GitHub Desktop.
Save Denisss025/03e37b82188b0ca15ca6 to your computer and use it in GitHub Desktop.
Declare a single function for several getter function name variations

Problem

Lets suppose, we want to create some function size(), which should take one argument and return some size.

It's easy, isn't it?

template <typename T>
size_t size(const T &val) { return val.size(); }

But now we want this function to work with objects that have getSize() function members.

template <typename T>
auto size(const T &val) -> decltype(val.size()) { return val.size(); }

template <typename T>
auto size(const T &val) -> decltype(val.getSize()) { return val.getSize(); }

Do we want more? Of course!!!

  • GetSize()
  • get_size()
  • Size()
  • more?

And what if...

class ... {
public:
    size_t size() const { ... };
    size_t get_size() const { return size(); }
};

Oops... Now we really need the std::enable_if<...>.

template <typename T, typename FDef>
constexpr auto has_func_size() -> decltype(std::declval<const T&>().size(), true) { 
    return std::is_same<FDef, &T::size>::value;
}
template <typename T, typename FDef>
constexpr auto has_func_get_size() -> decltype(std::declval<const T&>().get_size(), true) { 
    return std::is_same<FDef, &T::get_size>::value;
}

template <typename T, typename = enable_if_t<has_func_size<T, size_t (T::*)()const>(), int>>
auto size(const T &val) -> decltype(val.size()) { return val.size(); }

template <typename T, typename = enable_if_t<has_func_get_size<T, size_t (T::*)()const>() &&
    !has_func_size<T, size_t (T::*)()const>(), int>>
auto size(const T &val) -> decltype(val.getSize()) { return val.getSize(); }

And the same with the others...

I know, many of c++ programmers don't like macros. I don't like them too. But they're so helpfull sometimes.

Example compile and output

$ g++ -std=c++11 -O2 -g0 size_getter_test.cpp && ./a.out
test string size:   14
sss size:           1
string{} is empty?: true
sss{} is empty?:    false
// === detail/size_getter.hpp ===
#pragma once
#include <cstdint>
#include "detail/size_getter_defs.hpp"
namespace detail {
template <bool b, typename T>
using enable_if_t = typename std::enable_if<b, T>::type;
DEF_FUNCS(std::size_t (T::*)()const,
size, get_size, getSize, GetSize, Size)
DEF_FUNCS(bool (T::*)()const,
isEmpty, is_empty, empty, IsEmpty, Empty)
template <typename T, typename... Args>
static constexpr auto isEmpty(const T &val, Args...) ->
decltype(detail::size(val) == 0) {
return detail::size(val) == 0;
}
template <typename T>
using size_t = decltype(detail::size(std::declval<const T &>()));
using empty_t = bool;
} // namespace detail
// === detail/size_getter_defs.hpp ===
#pragma once
#include <utility> // for std::declval()
#include "va_defs.hpp"
#define HAS_MFUNC_(T, func, fdef) has_mem_func_##func<T, fdef>()
#define DEF_FUNC_TEMPL_IMPL(fdef, func) template <typename T, \
typename = enable_if_t<HAS_MFUNC_(T, func, fdef)
#define DEF_FUNC_IMPL_IMPL(fname, func) , int>> static constexpr \
auto fname(const T &val) -> decltype(val.func()) { return val.func(); }
#define NO_MFUNC_3(T, fdef, func) && !HAS_MFUNC_(T, func, fdef)
#define NO_MFUNC_4(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_3(T, fdef, __VA_ARGS__)
#define NO_MFUNC_5(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_4(T, fdef, __VA_ARGS__)
#define NO_MFUNC_6(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_5(T, fdef, __VA_ARGS__)
#define NO_MFUNC_7(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_6(T, fdef, __VA_ARGS__)
#define NO_MFUNC_8(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_7(T, fdef, __VA_ARGS__)
#define NO_MFUNC_9(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_8(T, fdef, __VA_ARGS__)
#define NO_MFUNC_10(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_9(T, fdef, __VA_ARGS__)
#define NO_MFUNC_11(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_10(T, fdef, __VA_ARGS__)
#define NO_MFUNC_12(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_11(T, fdef, __VA_ARGS__)
#define NO_MFUNC_13(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_12(T, fdef, __VA_ARGS__)
#define NO_MFUNC_14(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_13(T, fdef, __VA_ARGS__)
#define NO_MFUNC_15(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_14(T, fdef, __VA_ARGS__)
#define NO_MFUNC_16(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_15(T, fdef, __VA_ARGS__)
#define NO_MFUNC_17(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_16(T, fdef, __VA_ARGS__)
#define NO_MFUNC_18(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_17(T, fdef, __VA_ARGS__)
#define NO_MFUNC_19(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_18(T, fdef, __VA_ARGS__)
#define NO_MFUNC_20(T, fdef, func, ...) && !HAS_MFUNC_(T, func, fdef) NO_MFUNC_19(T, fdef, __VA_ARGS__)
#define DEF_HAS_MFUNC(fname) template <typename T, \
typename Fdef = decltype(&T::fname)> \
static constexpr auto has_mem_func_##fname() -> \
decltype(std::declval<T>().fname(), true) { \
return std::is_same<decltype(&T::fname), Fdef>::value; } \
template <typename T, typename Fdef, typename ...Args> \
static constexpr auto has_mem_func_##fname(Args...) -> bool { return false; }
#define DEF_FUNC_(fdef, fname, func, ...) DEF_FUNC_TEMPL_IMPL(fdef, func) \
VA_NUM_MACRO_CALL2(NO_MFUNC_, T, fdef, __VA_ARGS__) \
DEF_FUNC_IMPL_IMPL(fname, func)
#define DEF_FUNC_3(fdef, fname, func) DEF_HAS_MFUNC(func) DEF_FUNC_TEMPL_IMPL(fdef, func) DEF_FUNC_IMPL_IMPL(fname, func)
#define DEF_FUNC_4(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_3(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_5(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_4(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_6(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_5(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_7(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_6(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_8(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_7(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_9(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_8(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_10(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_9(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_11(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_10(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_12(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_11(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_13(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_12(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_14(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_13(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_15(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_14(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_16(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_15(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_17(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_16(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_18(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_17(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_19(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_18(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNC_20(fdef, fname, func, ...) DEF_HAS_MFUNC(func) DEF_FUNC_19(fdef, fname, __VA_ARGS__) DEF_FUNC_(fdef, fname, func, __VA_ARGS__)
#define DEF_FUNCS(fdef, fname, ...) VA_NUM_MACRO_CALL(DEF_FUNC_, fdef, fname, fname, __VA_ARGS__)
// === detail/va_defs.hpp ===
#pragma once
#define VA_CONCAT(_1, _2) VA_CONCAT_IMPL(_1, _2)
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__)
#define VA_CONCAT_IMPL_IMPL(_1, _2) _1##_2
#define VA_CONCAT_IMPL(_1, _2) VA_CONCAT_IMPL_IMPL(_1, _2)
#define VA_NUM_ARGS_IMPL_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \
_12, _13, _14, _15, _16, _17, _18, _19, _20, N, ...) N
#define VA_NUM_ARGS_IMPL(...) VA_NUM_ARGS_IMPL_IMPL(__VA_ARGS__, \
20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define VA_NUM_MACRO_CALL_IMPL(name, N, ...) VA_CONCAT(name, N)(__VA_ARGS__)
#define VA_NUM_MACRO_CALL(name, ...) \
VA_NUM_MACRO_CALL_IMPL(name, VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
#define VA_NUM_MACRO_CALL_IMPL2(name, N, ...) VA_CONCAT(name, N)(__VA_ARGS__)
#define VA_NUM_MACRO_CALL2(name, ...) \
VA_NUM_MACRO_CALL_IMPL2(name, VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
// === size.hpp ===
#pragma once
#include "detail/size_getter.hpp"
template <typename T>
static constexpr auto size(const T &val) -> decltype(detail::size(val)) {
return detail::size(val);
}
template <typename T>
static constexpr auto isEmpty(const T &val) -> decltype(detail::isEmpty(val)) {
return detail::isEmpty(val);
}
// === size_getter_test.cpp ===
#include <iostream>
#include <string>
#include "size.hpp"
struct SizeSizeSize {
size_t size() const { return 1; }
size_t get_size() const { return size(); }
size_t getSize() const { return size(); }
size_t GetSize() const { return size(); }
size_t Size() const { return size(); }
};
int main() {
std::cout << "test string size: " <<
size(std::string{"this is a test"}) << std::endl;
std::cout << "sss size: " <<
size(SizeSizeSize{}) << std::endl;
std::cout << std::boolalpha;
std::cout << "string{} is empty?: " << isEmpty(std::string{}) << std::endl;
std::cout << "sss{} is empty?: " << isEmpty(SizeSizeSize{}) << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment