Skip to content

Instantly share code, notes, and snippets.

@AndrewLipscomb
Created June 18, 2020 12:53
Show Gist options
  • Select an option

  • Save AndrewLipscomb/21f11d853cbb5a5f2dca2ccfe4cd122a to your computer and use it in GitHub Desktop.

Select an option

Save AndrewLipscomb/21f11d853cbb5a5f2dca2ccfe4cd122a to your computer and use it in GitHub Desktop.

Revisions

  1. AndrewLipscomb created this gist Jun 18, 2020.
    9 changes: 9 additions & 0 deletions main_a.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    #include "./templates_a.h"

    // Compile `gcc main_a.cpp`

    int main()
    {
    do_foo<LocalTypeA>(LocalTypeA());
    return 0;
    }
    33 changes: 33 additions & 0 deletions main_b.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    #include "./templates_b.h"

    #ifdef B_WITH_HELPER

    // Compile gcc main_b.cpp -DB_WITH_HELPER

    // This would normally be in its own impl - in the main for simplicity
    int do_foo(LocalTypeB bb)
    {
    // This is where I'd rather the detailed business logic be
    return 9001;
    }

    #endif

    #ifdef B_IN_IMPL

    // Compile gcc main_b.cpp -DB_IN_IMPL

    // This would normally be in its own impl - in the main for simplicity
    int do_foo(LocalTypeB bb)
    {
    return 9001;
    }

    #endif

    int main()
    {
    do_foo<double>(0.0);
    do_foo<LocalTypeB>(LocalTypeB());
    return 0;
    }
    15 changes: 15 additions & 0 deletions templates_a.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    #include <type_traits>

    class LocalTypeA { };

    template<typename T>
    std::enable_if_t<std::is_same<T, LocalTypeA>::value, int> do_foo(T bb)
    {
    // Some detailed business logic
    // specific to LocalTypeA and LocalTypeB that ideally isn't in a header
    // Key goal here is to be able to move this logic out of the header without
    // - more helper functions (ie: more header boilerplate per class) - ideally we just declare a template specialisation in the header
    // - exposing the lower classes to top level headers via fwd declaration
    // - breaking the resolution for funcs which _have_ to be in the header - like the std::is_fundamental one in templates_top.h
    return 2;
    }
    37 changes: 37 additions & 0 deletions templates_b.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,37 @@
    #include <type_traits>
    #include "templates_top.h"


    class LocalTypeB {
    public:
    bool the_val = false;
    };

    #ifdef B_WITH_HELPER

    template <typename T>
    struct helper< T, std::enable_if_t< std::is_same<T, LocalTypeB>::value > > : std::true_type {};

    template<>
    int do_foo(LocalTypeB bb);

    #endif

    #ifdef B_IN_IMPL

    template<>
    int do_foo(LocalTypeB bb);

    #else

    template<typename T>
    std::enable_if_t<std::is_same<T, LocalTypeB>::value, int> do_foo(T bb)
    {
    // Some detailed business logic here
    // specific to LocalTypeB that ideally isn't in a header
    // Also - we need to invoke generic impl of the same template further up
    return do_foo<bool>(bb.the_val);
    }


    #endif
    33 changes: 33 additions & 0 deletions templates_top.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    #include <type_traits>

    #ifdef B_WITH_HELPER

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

    template<typename T>
    std::enable_if_t<helper<T>::value, int> do_foo(T bb)
    {
    static_assert(std::is_same<T, void>::value && false, "Never do this");
    }

    #endif

    #ifdef B_IN_IMPL

    template<typename T>
    int do_foo(T bb)
    {
    static_assert(std::is_same<T, void>::value && false, "Never do this");
    }

    #endif


    template<typename T>
    std::enable_if_t<std::is_fundamental<T>::value, int> do_foo(T bb)
    {
    // Some generic business logic for all fundamental types here
    // OK to live in a header, not much we can do here
    return 0;
    }