Skip to content

Instantly share code, notes, and snippets.

@AndrewLipscomb
Created June 18, 2020 12:53
Show Gist options
  • Save AndrewLipscomb/21f11d853cbb5a5f2dca2ccfe4cd122a to your computer and use it in GitHub Desktop.
Save AndrewLipscomb/21f11d853cbb5a5f2dca2ccfe4cd122a to your computer and use it in GitHub Desktop.
Better C++ SE question
#include "./templates_a.h"
// Compile `gcc main_a.cpp`
int main()
{
do_foo<LocalTypeA>(LocalTypeA());
return 0;
}
#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;
}
#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;
}
#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
#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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment