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.

Revisions

  1. Denisss025 revised this gist Mar 1, 2016. 2 changed files with 72 additions and 5 deletions.
    5 changes: 0 additions & 5 deletions OUTPUT.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +0,0 @@
    $ 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
    72 changes: 72 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,72 @@
    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?

    ```cpp
    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.
    ```cpp
    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...

    ```cpp
    class ... {
    public:
    size_t size() const { ... };
    size_t get_size() const { return size(); }
    };
    ```
    Oops... Now we really need the `std::enable_if<...>`.
    ```cpp
    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
  2. Denisss025 revised this gist Mar 1, 2016. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions OUTPUT.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    $ 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
  3. Denisss025 revised this gist Mar 1, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion size_getter_test.cpp
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    #include <iostream>
    #include <string>
    #include "SizeGetterIf.hpp"
    #include "size.hpp"

    struct SizeSizeSize {
    size_t size() const { return 1; }
  4. Denisss025 created this gist Mar 1, 2016.
    29 changes: 29 additions & 0 deletions detail-size_getter.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,29 @@
    // === 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
    64 changes: 64 additions & 0 deletions detail-size_getter_defs.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,64 @@
    // === 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__)
    21 changes: 21 additions & 0 deletions detail-va_defs.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,21 @@
    // === 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__)
    14 changes: 14 additions & 0 deletions size.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,14 @@
    // === 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);
    }
    25 changes: 25 additions & 0 deletions size_getter_test.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,25 @@
    // === size_getter_test.cpp ===

    #include <iostream>
    #include <string>
    #include "SizeGetterIf.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;
    }