C ++ templates are usually assimilated to bloat creators, and the idea of ββShim deals precisely with what makes the template just a thin shell over a regular function. This is a really great way to reduce swelling.
For example, you can use a simple gasket:
// // Shim interface // struct Interface { virtual void print(std::ostream& out) const = 0; }; // struct Interface std::ostream& operator<<(std::ostream& out, Interface const& i) { i.print(out); return out; } template <typename T> struct IT: public Interface { IT(T const& t): _t(t) {} virtual void print(std::ostream& out) const { out << _t; } T const& _t; }; template <typename T> IT<T> shim(T const& t) { return IT<T>(t); }
Now I can use it like this:
void print_impl(Interface const& t); template <typename T> void print(T const& t) { print_impl(shim(t)); }
And no matter how print_impl implemented, print remains very lightweight and needs to be embedded. Easy peasy.
C ++ 11 introduces variable templates. A typical motivation is to reimplement all unsafe C variations with C ++ 11 variable templates, even Wikipedia offers this with a printf implementation .
Unfortunately, the Wikipedia implementation is not related to positional arguments: a type that allows you to specify a third parameter there, etc ... It would be easy if we had a function with this prototype:
void printf_impl(char const* format, Interface const* array, size_t size);
or similar.
Now , as we modem from the source interface :
template <typename... T> void printf(char const* format, T const&... t);
in the signature above?
One of the difficulties with pads is that they rely on binding to const-ref behavior to extend the life time of a temporary shell created sufficiently without the need to dynamically allocate memory (they would not be cheap if they did).
It seems difficult though to get this binding + array conversion in one step. Moreover, the language does not allow arrays of links (and a pointer to links).
I have a beginning solution for those interested:
// // printf (or it could be!) // void printf_impl(char const*, Interface const** array, size_t size) { for (size_t i = 0; i != size; ++i) { std::cout << *(array[i]); } std::cout << "\n"; } template <typename... T> void printf_bridge(char const* format, T const&... t) { Interface const* array[sizeof...(t)] = { (&t)... }; printf_impl(format, array, sizeof...(t)); } template <typename... T> void printf(char const* format, T const&... t) { printf_bridge(format, ((Interface const&)shim(t))...); }
however, you will notice the introduction of an extra step, which is a little annoying. However, it works .
I would really appreciate it if someone suggests a better implementation.
@Potatoswatter suggests using initializer lists that help a little (there is no range for them).
void printf_impl(char const*, std::initializer_list<Interface const*> array) { for (Interface const* e: list) { std::cout << *e; } std::cout << "\n"; } template <typename... T> void printf_bridge(char const* format, T const&... t) { printf_impl(format, {(&t)...}); }
But still does not solve the problem of intermediate function.