Captured in-line array in constexpr variable gets lost on runtime - c++

I'm trying to create an [int/enum]-to-text mapping class with as little overhead as possible for it's users. It's constructor should be passed a list of value-to-text mappings, which can be queried afterwards. Created objects should be constexpr and have an optional size argument, which allows the compiler to optionally check at compile time if the number of passed mappings matches what is expected. This is especially useful as an extra safety measure when used with enums -- that is: this way you can force a compile error if you neglect to add a mapping for newly added enum values. It should work with C++14 under Visual Studio 2019 and Xcode 9 and 12.
My current stab at this is the code below. However, under Visual Studio 2019 at least, the passed array of mappings is not correctly captured in the m_mappings member variable. When you run this code, m_mappings points to a random memory address, so any output you get is wrong (if it doesn't outright crash).
#include <iostream>
template <typename Type>
struct Mapping {
Type value;
const char* text;
};
template <typename Type, Type maxValue = Type(-1)>
class Mapper {
public:
template <size_t numMappings>
explicit constexpr Mapper(const Mapping<Type>(&mappings)[numMappings]) :
m_mappings(mappings),
m_numMappings(numMappings) {
static_assert(
int(maxValue) == -1 || numMappings == int(maxValue) + 1,
"Some mappings are missing!"
);
}
const char* Map(Type value) const {
for (size_t mappingNr = 0; mappingNr < m_numMappings; ++mappingNr)
if (m_mappings[mappingNr].value == value)
return m_mappings[mappingNr].text;
return "?";
}
private:
const Mapping<Type>* m_mappings;
const size_t m_numMappings;
};
enum class TestEnum {
a,
b,
c,
maxValue = c
};
int main() {
constexpr Mapper<int> intMapper_noCheck({
{ 11, "a" },
{ 5, "b" },
{ 26, "x" }
});
std::cout << intMapper_noCheck.Map(10);
constexpr Mapper<int, 3> intMapper_check({
{ 0, "z" },
{ 1, "f" },
{ 2, "t" },
{ 3, "#" }
});
std::cout << intMapper_check.Map(2);
// if we'd pass e.g. TestEnum::b here, we get a nice compile time error
constexpr Mapper<TestEnum, TestEnum::maxValue> enumMapper({
{ TestEnum::a, "-" },
{ TestEnum::b, "-" },
{ TestEnum::c, "+" }
});
std::cout << enumMapper.Map(TestEnum::b);
// expected output by now: "?t-"
std::cin.get();
return 0;
}
A possible solution is to capture the mapping array in a separate constexpr variable, and pass that to the mapper objects, like so:
constexpr Mapping<TestEnum> enumMapping[] = {
{ TestEnum::a, "-" },
{ TestEnum::b, "-" },
{ TestEnum::c, "+" }
};
constexpr Mapper<TestEnum, TestEnum::maxValue> enumMapper(enumMapping);
std::cout << enumMapper.Map(TestEnum::b);
This way the mappings do get preserved and the output is correct. However, I find this extra layer makes it much more 'messy'...
The complicating factor here is that the passed in array's size must be captured in a constexpr-friendly way, and I do not want to have to specify it separately by hand.
Using a fixed size array with the size specified in the constructor's template argument is one way of doing it, but when passing an array in-line it is thus not accessible at runtime.
Another version would be to pass (and store) a std::initializer_list, but you can't static_assert on it's size method. As a workaround we could also initialize m_mappings like m_mappings(sizeMatches? mappings: throw "mismatch!"), but that way non-constexpr objects may perform nasty throws at runtime (and unfortunately the rest of the code base isn't exactly exception safe).
I contemplated using a std::array instead (that one's size is constexpr accessible), but then there is no way to pass the used size to m_mappings (the size is only known to the constructor template, and not to the class template).
I also contemplated using a template parameter pack for the constructor so users can pass the loose value-and-text args two-by-two. But then how do I stuff these into m_mappings? I'd have to e.g. make m_mappings a std::vector to do so, but that's not constexpr-compatible.
What could be another option whilst keeping it nice and clean like in my first version?

The reason it fails is that you store a pointer to the array passed to the constructor for later use.
But in your compact cases, that array no longer exists after the constructor has run. So you need to do some allocation (which might not be constexpr-friendly in all compilers) and copying. The fact that you use a char* instead of a std::string further adds to this problem - there too there is no guarantee that the pointed-to string still exists when you use it.
Also, unless this is for some sort of coursework, consider looking at the constexpr implementations of sets and maps provided by https://github.com/serge-sans-paille/frozen

After some more tampering I came up with a solution where I just copy over the passed mappings into a plain old array member. I also tried to use an std::array, but it just isn't constexpr-friendly enough in C++14.
What I tried previously was to automatically capture the mapping list size in the templated constructor (numMappings is deduced by the compiler), and then match it to the specified expected number of mappings from the class template (maxValue). But now the class template itself needs to know the number of mappings we're going to pass, so that it can reserve storage for the copy. So I've also repurposed the maxValue parameter to represent exactly that.
A drawback is thus that you now always need to count out manually how many mappings you're going to pass, which is a pain when mapping over large discontinuous int ranges where you'd really like not to care about that detail. For enums nothing really changes though, and I mainly wrote this class for handling enums.
So it's not a 100% perfect fit with the question, but it'll do I suppose... ah well.
#include <iostream>
template <typename Type>
struct Mapping {
Type value;
const char* text;
};
template <typename Type, Type maxValue>
class Mapper {
public:
template <size_t numMappings>
explicit constexpr Mapper(const Mapping<Type>(&mappings)[numMappings]) :
m_mappings{} {
constexpr int correctNumMappings{ int(maxValue) + 1 };
static_assert(numMappings <= correctNumMappings, "Too many mappings given!");
static_assert(numMappings >= correctNumMappings, "Some mappings are missing!");
for (size_t mappingNr = 0; mappingNr < numMappings; ++mappingNr)
m_mappings[mappingNr] = mappings[mappingNr];
}
const char* Map(Type value) const {
for (const Mapping<Type>& mapping : m_mappings)
if (mapping.value == value)
return mapping.text;
return "?";
}
private:
Mapping<Type> m_mappings[int(maxValue) + 1];
};
enum class TestEnum {
a,
b,
c,
maxValue = c
};
int main() {
constexpr Mapper<int, 3> intMapper_check({
{ 0, "z" },
{ 1, "f" },
{ 2, "t" },
{ 3, "#" }
});
std::cout << intMapper_check.Map(2) << "\n";
constexpr Mapper<TestEnum, TestEnum::maxValue> enumMapper({
{ TestEnum::a, "-" },
{ TestEnum::b, "-" },
{ TestEnum::c, "+" }
});
std::cout << enumMapper.Map(TestEnum::b) << "\n";
std::cin.get();
return 0;
}

Related

Get tuple element at runtime

I know that it is possible to get a random tuple element at runtime. Behind the scenes, make_integer_sequence and integer_sequence can get all elements at compile time and offer access to these elements at runtime.
But my problem is that it seems only to be possible to access the elements of a random index only with a lambda or function pointer. I would like to get the lambda to return the element-reference so that I could get something like this:
auto myElement = runtime_get(mytuple, 5);
I don't know how I could do this. Working with templates isn't that new to me but templates can get very difficult to understand if they become complex. I'm trying to learn more about them by playing a little bit with the tuple-stuff.
I think, this should work: runtime_get<std::string>(0, mytuple), so the type is predetermined.
Yes, this is certainly possible, but you need to do something if the runtime index isn't the right type. For example, throw an exception.
Here's one sample implementation, but note that I condensed it at the expense of some readability. Member function pointers and templated lambdas is possibly the worst combination of features the language has to offer, but it was pretty concise (live example):
template<typename Result, typename... Ts>
auto runtime_get(std::size_t i, std::tuple<Ts...>& t) -> Result& {
using Tuple = std::tuple<Ts...>;
// A set of functions to get the element at one specific index
auto get_at_index = []<std::size_t I>(Tuple& tuple) -> Result& {
if constexpr (std::is_same_v<std::tuple_element_t<I, Tuple>, Result>) {
return std::get<I>(tuple);
} else {
throw std::runtime_error("Index does not contain the right type");
}
};
// Regular index_sequence trick to get a pack of indices
return [&]<std::size_t... Is>(std::index_sequence<Is...>) -> Result& {
// The type of a single member function pointer of the closure type, using awkward memfun syntax
using FPtr = auto(decltype(get_at_index)::*)(Tuple&) const -> Result&;
// An array of said memfun pointers, each for one known index
FPtr fptrs[sizeof...(Ts)]{&decltype(get_at_index)::template operator()<Is>...};
// Invoke the correct pointer
return (get_at_index.*(fptrs[i]))(t);
}(std::index_sequence_for<Ts...>());
}
int main() {
std::tuple<std::string, int, double, std::string> t{"abc", 2, 5.9, "def"};
for (int i = 0; i < 4; ++i) {
try {
std::string& s = runtime_get<std::string>(i, t);
std::cout << "Success: " << s << '\n';
} catch (const std::runtime_error& ex) {
std::cout << "Failure: " << ex.what() << '\n';
}
}
}
Success: abc
Failure: Index does not contain the right type
Failure: Index does not contain the right type
Success: def
This is just the lvalue reference version, you might need other overloads. If you want a more reusable bit of trickery for the runtime-to-compile-time index conversion that you can hide away in a header, check out the std::call proposal.
Note also that this can be built out of a callback-based solution:
template<typename Result, typename... Ts>
auto runtime_get(std::size_t i, std::tuple<Ts...>& t) -> Result& {
return callback_get(i, t, [](auto& elem) -> Result& { /* same implementation as get_at_index */ });
}
The key point is that types must be resolved at compile-time. In the case of a template as a callback, that callback is being instantiated for every possible type regardless of whether that instatiation is actually used at runtime. You end up with N different callback functions, one for each possible case the program could encounter. There's no analogue for a simple variable.
Therefore, you need to condense N possibilities down to the same behaviour. This can be done as above by choosing a specific type and throwing (or returning an empty optional) on a mismatch. This can also be done by returning a variant, which covers all possible types, but doesn't actually bring you any closer to overcoming the impossible part of this problem—std::visit uses the same callback mechanism where each possible type needs to be compiled against the given callback.

Creating compile-time Key-Value map in C++

I have tried to create a compile-time simple Key-Value map in C++. I'm compiling with /std:c++11.
(Using IAR compiler for embedded code and only cpp++11 is supported at the moment)
I've learnt a little bit about meta-programming.
I don't want my map to have a default value, if key is not found,
like this post: How to build a compile-time key/value store?
I want to get compiler error, if in my code I'm trying to get a value which is not stored in the map.
Here is what I've done:
#include <iostream>
template <int kk, int vv>
struct KeyValue
{
static const int k = kk, v = vv;
};
// Declaration
template <typename kv, typename...>
struct CompileTimeMap;
// Recursive Definition
template<typename kv, typename... rest>
struct CompileTimeMap<kv, rest...>
{
template<int k_input>
struct get
{
static const int val = (k_input == kv::k) ? kv::v : CompileTimeMap<rest...>::get<k_input>::val;
};
};
// Base Definition
template <typename kv>
struct CompileTimeMap<kv>
{
template<int k_input>
struct get
{
static const int val = (k_input == kv::k) ? kv::v;
};
};
// ----------------------------- Main -----------------------------
typedef CompileTimeMap<KeyValue<10, 20>, KeyValue<11, 21>, KeyValue<23, 7>> mymap;
int main()
{
// This calles should be ok !! :)
std::cout << mymap::get<10>::val << std::endl;
std::cout << mymap::get<11>::val << std::endl;
std::cout << mymap::get<23>::val << std::endl;
// This line should resolve a compile error !! (there is no key of 33)
std::cout << mymap::get<33>::val << std::endl;
}
I get the following error: error C2131: expression did not evaluate to a constant.
How can I make this work? Many thanks :)
Don't write a template metaprogram, where it is not necessary. Try this simple solution (CTMap stands for compile time map):
template <class Key, class Value, int N>
class CTMap {
public:
struct KV {
Key key;
Value value;
};
constexpr Value operator[] (Key key) const
{
return Get (key);
}
private:
constexpr Value Get (Key key, int i = 0) const
{
return i == N ?
KeyNotFound () :
pairs[i].key == key ? pairs[i].value : Get (key, i + 1);
}
static Value KeyNotFound () // not constexpr
{
return {};
}
public:
KV pairs[N];
};
constexpr CTMap<int, int, 3> ctMap {{ { 10, 20 }, { 11, 21 }, { 23, 7 } }};
static_assert (ctMap[10] == 20, "Error.");
static_assert (ctMap[11] == 21, "Error.");
static_assert (ctMap[23] == 7, "Error.");
// constexpr auto compilationError = ctMap[404];
You will get a compilation error, if you uncomment the last line (live demo). The compiler will direct you to the KeyNotFound () : line, from
which the reason of the failure should be obvious.
Remarks
The member variable pairs is made public, to make it possible to initialize the map with list-initialization.
The given N and the number of pairs that initialize CTMap should match. If N is less, you get a compilation error. If N is greater, zero-initialized pairs ({ 0, 0 }) will be silently added to pairs. Pay attention to this.
The (compiler generated) constructor does not check for duplicate keys. operator[] will find the first, but the intended usage is that you do not initialize CTMap with duplicate keys.
Recursion is not necessary in C++14. We can write a for loop in a constexpr function (live demo). The linked implementation gives another idea for giving a compiler error in case the key is not found: an exception is thrown. The member variable pairs is made private.
Intended to be used in compile time
This is a linear map, and parameters are passed by value. My intention was that the map will be used in compile time evaluated code, where this should not be a problem.
Note also that when evaluated in run time, this class won't give any feedback if the key is not found in the map.
Let's take a closer look of how ctMap[10] works in different situations. I have tried the following with three compilers (MSVC v19.24, clang 10.0.0, gcc 9.3).
constexpr int C = ctMap[10]; – The global constant C will be initialized with 20 even in debug builds. No computation is made during run-time. Note that to ensure, that the global will be created, you have to take its address somewhere. If you use the value of C, its value (20) will be substituted where it is used, and C won't be created in the object file even in debug builds.
int Foo () { return ctMap[10]; } – In debug builds operator[] will be called. In release builds MSVC inlines operator[] to Foo, i.e. eliminates one call, but the resulting code has linear complexity (the compiler is not forced to do the computation in compile time, and code optimization is poor in MSVC). Clang and gcc compiles a return 20;.
And this is how ctMap[404] works (with the same three compilers):
constexpr int C = ctMap[404]; – Does not compile, as mentioned above.
int Foo () { return ctMap[404]; } – The same remarks apply as for ctMap[10], but Foo will return 0. You cannot know, that 404 was not in the map. To get the compilation error, Foo has to be constexpr and forced to be evaluated in compile time by e.g. assigning it to a constexpr variable or an enumerator, using it in a template argument, as a size of a C array, in a static_assert, etc.

Avoid memory allocation with std::function and member function

This code is just for illustrating the question.
#include <functional>
struct MyCallBack {
void Fire() {
}
};
int main()
{
MyCallBack cb;
std::function<void(void)> func = std::bind(&MyCallBack::Fire, &cb);
}
Experiments with valgrind shows that the line assigning to func dynamically allocates about 24 bytes with gcc 7.1.1 on linux.
In the real code, I have a few handfuls of different structs all with a void(void) member function that gets stored in ~10 million std::function<void(void)>.
Is there any way I can avoid memory being dynamically allocated when doing std::function<void(void)> func = std::bind(&MyCallBack::Fire, &cb); ? (Or otherwise assigning these member function to a std::function)
Unfortunately, allocators for std::function has been dropped in C++17.
Now the accepted solution to avoid dynamic allocations inside std::function is to use lambdas instead of std::bind. That does work, at least in GCC - it has enough static space to store the lambda in your case, but not enough space to store the binder object.
std::function<void()> func = [&cb]{ cb.Fire(); };
// sizeof lambda is sizeof(MyCallBack*), which is small enough
As a general rule, with most implementations, and with a lambda which captures only a single pointer (or a reference), you will avoid dynamic allocations inside std::function with this technique (it is also generally better approach as other answer suggests).
Keep in mind, for that to work you need guarantee that this lambda will outlive the std::function. Obviously, it is not always possible, and sometime you have to capture state by (large) copy. If that happens, there is no way currently to eliminate dynamic allocations in functions, other than tinker with STL yourself (obviously, not recommended in general case, but could be done in some specific cases).
As an addendum to the already existent and correct answer, consider the following:
MyCallBack cb;
std::cerr << sizeof(std::bind(&MyCallBack::Fire, &cb)) << "\n";
auto a = [&] { cb.Fire(); };
std::cerr << sizeof(a);
This program prints 24 and 8 for me, with both gcc and clang. I don't exactly know what bind is doing here (my understanding is that it's a fantastically complicated beast), but as you can see, it's almost absurdly inefficient here compared to a lambda.
As it happens, std::function is guaranteed to not allocate if constructed from a function pointer, which is also one word in size. So constructing a std::function from this kind of lambda, which only needs to capture a pointer to an object and should also be one word, should in practice never allocate.
Run this little hack and it probably will print the amount of bytes you can capture without allocating memory:
#include <iostream>
#include <functional>
#include <cstring>
void h(std::function<void(void*)>&& f, void* g)
{
f(g);
}
template<size_t number_of_size_t>
void do_test()
{
size_t a[number_of_size_t];
std::memset(a, 0, sizeof(a));
a[0] = sizeof(a);
std::function<void(void*)> g = [a](void* ptr) {
if (&a != ptr)
std::cout << "malloc was called when capturing " << a[0] << " bytes." << std::endl;
else
std::cout << "No allocation took place when capturing " << a[0] << " bytes." << std::endl;
};
h(std::move(g), &g);
}
int main()
{
do_test<1>();
do_test<2>();
do_test<3>();
do_test<4>();
}
With gcc version 8.3.0 this prints
No allocation took place when capturing 8 bytes.
No allocation took place when capturing 16 bytes.
malloc was called when capturing 24 bytes.
malloc was called when capturing 32 bytes.
Many std::function implementations will avoid allocations and use space inside the function class itself rather than allocating if the callback it wraps is "small enough" and has trivial copying. However, the standard does not require this, only suggests it.
On g++, a non-trivial copy constructor on a function object, or data exceeding 16 bytes, is enough to cause it to allocate. But if your function object has no data and uses the builtin copy constructor, then std::function won't allocate.
Also, if you use a function pointer or a member function pointer, it won't allocate.
While not directly part of your question, it is part of your example.
Do not use std::bind. In virtually every case, a lambda is better: smaller, better inlining, can avoid allocations, better error messages, faster compiles, the list goes on. If you want to avoid allocations, you must also avoid bind.
I propose a custom class for your specific usage.
While it's true that you shouldn't try to re-implement existing library functionality because the library ones will be much more tested and optimized, it's also true that it applies for the general case. If you have a particular situation like in your example and the standard implementation doesn't suite your needs you can explore implementing a version tailored to your specific use case, which you can measure and tweak as necessary.
So I have created a class akin to std::function<void (void)> that works only for methods and has all the storage in place (no dynamic allocations).
I have lovingly called it Trigger (inspired by your Fire method name). Please do give it a more suited name if you want to.
// helper alias for method
// can be used in user code
template <class T>
using Trigger_method = auto (T::*)() -> void;
namespace detail
{
// Polymorphic classes needed for type erasure
struct Trigger_base
{
virtual ~Trigger_base() noexcept = default;
virtual auto placement_clone(void* buffer) const noexcept -> Trigger_base* = 0;
virtual auto call() -> void = 0;
};
template <class T>
struct Trigger_actual : Trigger_base
{
T& obj;
Trigger_method<T> method;
Trigger_actual(T& obj, Trigger_method<T> method) noexcept : obj{obj}, method{method}
{
}
auto placement_clone(void* buffer) const noexcept -> Trigger_base* override
{
return new (buffer) Trigger_actual{obj, method};
}
auto call() -> void override
{
return (obj.*method)();
}
};
// in Trigger (bellow) we need to allocate enough storage
// for any Trigger_actual template instantiation
// since all templates basically contain 2 pointers
// we assume (and test it with static_asserts)
// that all will have the same size
// we will use Trigger_actual<Trigger_test_size>
// to determine the size of all Trigger_actual templates
struct Trigger_test_size {};
}
struct Trigger
{
std::aligned_storage_t<sizeof(detail::Trigger_actual<detail::Trigger_test_size>)>
trigger_actual_storage_;
// vital. We cannot just cast `&trigger_actual_storage_` to `Trigger_base*`
// because there is no guarantee by the standard that
// the base pointer will point to the start of the derived object
// so we need to store separately the base pointer
detail::Trigger_base* base_ptr = nullptr;
template <class X>
Trigger(X& x, Trigger_method<X> method) noexcept
{
static_assert(sizeof(trigger_actual_storage_) >=
sizeof(detail::Trigger_actual<X>));
static_assert(alignof(decltype(trigger_actual_storage_)) %
alignof(detail::Trigger_actual<X>) == 0);
base_ptr = new (&trigger_actual_storage_) detail::Trigger_actual<X>{x, method};
}
Trigger(const Trigger& other) noexcept
{
if (other.base_ptr)
{
base_ptr = other.base_ptr->placement_clone(&trigger_actual_storage_);
}
}
auto operator=(const Trigger& other) noexcept -> Trigger&
{
destroy_actual();
if (other.base_ptr)
{
base_ptr = other.base_ptr->placement_clone(&trigger_actual_storage_);
}
return *this;
}
~Trigger() noexcept
{
destroy_actual();
}
auto destroy_actual() noexcept -> void
{
if (base_ptr)
{
base_ptr->~Trigger_base();
base_ptr = nullptr;
}
}
auto operator()() const
{
if (!base_ptr)
{
// deal with this situation (error or just ignore and return)
}
base_ptr->call();
}
};
Usage:
struct X
{
auto foo() -> void;
};
auto test()
{
X x;
Trigger f{x, &X::foo};
f();
}
Warning: only tested for compilation errors.
You need to thoroughly test it for correctness.
You need to profile it and see if it has a better performance than other solutions. The advantage of this is because it's in house cooked you can make tweaks to the implementation to increase performance on your specific scenarios.
As #Quuxplusone mentioned in their answer-as-a-comment, you can use inplace_function here. Include the header in your project, and then use like this:
#include "inplace_function.h"
struct big { char foo[20]; };
static stdext::inplace_function<void(), 8> inplacefunc;
static std::function<void()> stdfunc;
int main() {
static_assert(sizeof(inplacefunc) == 16);
static_assert(sizeof(stdfunc) == 32);
inplacefunc = []() {};
// fine
struct big a;
inplacefunc = [a]() {};
// test.cpp:15:24: required from here
// inplace_function.h:237:33: error: static assertion failed: inplace_function cannot be constructed from object with this (large) size
// 237 | static_assert(sizeof(C) <= Capacity,
// | ~~~~~~~~~~^~~~~~~~~~~
// inplace_function.h:237:33: note: the comparison reduces to ‘(20 <= 8)’
}

Calling templated function with type unknown until runtime

I have a this function to read 1d arrays from an unformatted fortran file:
template <typename T>
void Read1DArray(T* arr)
{
unsigned pre, post;
file.read((char*)&pre, PREPOST_DATA);
for(unsigned n = 0; n < (pre/sizeof(T)); n++)
file.read((char*)&arr[n], sizeof(T));
file.read((char*)&post, PREPOST_DATA);
if(pre!=post)
std::cout << "Failed read fortran 1d array."<< std::endl;
}
I call this like so:
float* new_array = new float[sizeof_fortran_array];
Read1DArray(new_array);
Assume Read1DArray is part of a class, which contains an ifstream named 'file', and sizeof_fortran_array is already known. (And for those not quite so familiar with fortran unformatted writes, the 'pre' data indicates how long the array is in bytes, and the 'post' data is the same)
My issue is that I have a scenario where I may want to call this function with either a float* or a double*, but this will not be known until runtime.
Currently what I do is simply have a flag for which data type to read, and when reading the array I duplicate the code something like this, where datatype is a string set at runtime:
if(datatype=="float")
Read1DArray(my_float_ptr);
else
Read1DArray(my_double_ptr);
Can someone suggest a method of rewriting this so that I dont have to duplicate the function call with the two types? These are the only two types it would be necessary to call it with, but I have to call it a fair few times and I would rather not have this duplication all over the place.
Thanks
EDIT:
In response to the suggestion to wrap it in a call_any_of function, this wouldnt be enough because at times I do things like this:
if(datatype=="float")
{
Read1DArray(my_float_ptr);
Do_stuff(my_float_ptr);
}
else
{
Read1DArray(my_double_ptr);
Do_stuff(my_double_ptr);
}
// More stuff happening in between
if(datatype=="float")
{
Read1DArray(my_float_ptr);
Do_different_stuff(my_float_ptr);
}
else
{
Read1DArray(my_double_ptr);
Do_different_stuff(my_double_ptr);
}
If you think about the title you will realize that there is a contradiction in that the template instantiation is performed at compile time but you want to dispatch based on information available only at runtime. At runtime you cannot instantiate a template, so that is impossible.
The approach you have taken is actually the right one: instantiate both options at compile time, and decide which one to use at runtime with the available information. That being said you might want to think your design.
I imagine that not only reading but also processing will be different based on that runtime value, so you might want to bind all the processing in a (possibly template) function for each one of the types and move the if further up the call hierarchy.
Another approach to avoid having to dispatch based on type to different instantiations of the template would be to loose some of the type safety and implement a single function that takes a void* to the allocated memory and a size argument with the size of the type in the array. Note that this will be more fragile, and it does not solve the overall problem of having to act on the different arrays after the data is read, so I would not suggest following this path.
Because you don't know which code path to take until runtime, you'll need to set up some kind of dynamic dispatch. Your current solution does this using an if-else which must be copied and pasted everywhere it is used.
An improvement would be to generate a function that performs the dispatch. One way to achieve this is by wrapping each code path in a member function template, and using an array of member function pointers that point to specialisations of that member function template. [Note: This is functionally equivalent to dynamic dispatch using virtual functions.]
class MyClass
{
public:
template <typename T>
T* AllocateAndRead1DArray(int sizeof_fortran_array)
{
T* ptr = new T[sizeof_fortran_array];
Read1DArray(ptr);
return ptr;
}
template <typename T>
void Read1DArrayAndDoStuff(int sizeof_fortran_array)
{
Do_stuff(AllocateAndRead1DArray<T>(sizeof_fortran_array));
}
template <typename T>
void Read1DArrayAndDoOtherStuff(int sizeof_fortran_array)
{
Do_different_stuff(AllocateAndRead1DArray<T>(sizeof_fortran_array));
}
// map a datatype to a member function that takes an integer parameter
typedef std::pair<std::string, void(MyClass::*)(int)> Action;
static const int DATATYPE_COUNT = 2;
// find the action to perform for the given datatype
void Dispatch(const Action* actions, const std::string& datatype, int size)
{
for(const Action* i = actions; i != actions + DATATYPE_COUNT; ++i)
{
if((*i).first == datatype)
{
// perform the action for the given size
return (this->*(*i).second)(size);
}
}
}
};
// map each datatype to an instantiation of Read1DArrayAndDoStuff
MyClass::Action ReadArrayAndDoStuffMap[MyClass::DATATYPE_COUNT] = {
MyClass::Action("float", &MyClass::Read1DArrayAndDoStuff<float>),
MyClass::Action("double", &MyClass::Read1DArrayAndDoStuff<double>),
};
// map each datatype to an instantiation of Read1DArrayAndDoOtherStuff
MyClass::Action ReadArrayAndDoOtherStuffMap[MyClass::DATATYPE_COUNT] = {
MyClass::Action("float", &MyClass::Read1DArrayAndDoOtherStuff<float>),
MyClass::Action("double", &MyClass::Read1DArrayAndDoOtherStuff<double>),
};
int main()
{
MyClass object;
// call MyClass::Read1DArrayAndDoStuff<float>(33)
object.Dispatch(ReadArrayAndDoStuffMap, "float", 33);
// call MyClass::Read1DArrayAndDoOtherStuff<double>(542)
object.Dispatch(ReadArrayAndDoOtherStuffMap, "double", 542);
}
If performance is important, and the possible set of types is known at compile time, there are a few further optimisations that could be performed:
Change the string to an enumeration that represents all the possible data types and index the array of actions by that enumeration.
Give the Dispatch function template parameters that allow it to generate a switch statement to call the appropriate function.
For example, this can be inlined by the compiler to produce code that is (generally) more optimal than both the above example and the original if-else version in your question.
class MyClass
{
public:
enum DataType
{
DATATYPE_FLOAT,
DATATYPE_DOUBLE,
DATATYPE_COUNT
};
static MyClass::DataType getDataType(const std::string& datatype)
{
if(datatype == "float")
{
return MyClass::DATATYPE_FLOAT;
}
return MyClass::DATATYPE_DOUBLE;
}
// find the action to perform for the given datatype
template<typename Actions>
void Dispatch(const std::string& datatype, int size)
{
switch(getDataType(datatype))
{
case DATATYPE_FLOAT: return Actions::FloatAction::apply(*this, size);
case DATATYPE_DOUBLE: return Actions::DoubleAction::apply(*this, size);
}
}
};
template<void(MyClass::*member)(int)>
struct Action
{
static void apply(MyClass& object, int size)
{
(object.*member)(size);
}
};
struct ReadArrayAndDoStuff
{
typedef Action<&MyClass::Read1DArrayAndDoStuff<float>> FloatAction;
typedef Action<&MyClass::Read1DArrayAndDoStuff<double>> DoubleAction;
};
struct ReadArrayAndDoOtherStuff
{
typedef Action<&MyClass::Read1DArrayAndDoOtherStuff<float>> FloatAction;
typedef Action<&MyClass::Read1DArrayAndDoOtherStuff<double>> DoubleAction;
};
int main()
{
MyClass object;
// call MyClass::Read1DArrayAndDoStuff<float>(33)
object.Dispatch<ReadArrayAndDoStuff>("float", 33);
// call MyClass::Read1DArrayAndDoOtherStuff<double>(542)
object.Dispatch<ReadArrayAndDoOtherStuff>("double", 542);
}

generic non-invasive cache wrapper

I'm trying create a class which adds functionality to a generic class, without directly interfacing with the wrapped class. A good example of this would be a smart pointer. Specifically, I'd like to create a wrapper which caches all the i/o for one (or any?) method invoked through the wrapper. Ideally, the cache wrapper have the following properties:
it would not require the wrapping class to be changed in any way (i.e. generic)
it would not require the wrapped class to be changed in any way (i.e. generic)
it would not change the interface or syntax for using the object significantly
For example, it would be really nice to use it like this:
CacheWrapper<NumberCruncher> crunchy;
...
// do some long and ugly calculation, caching method input/output
result = crunchy->calculate(input);
...
// no calculation, use cached result
result = crunchy->calculate(input);
although something goofy like this would be ok:
result = crunchy.dispatch (&NumberCruncher::calculate, input);
I feel like this should be possible in C++, although possibly with some syntactic gymnastics somewhere along the line.
Any ideas?
I think I have the answer you are seeking, or, at least, I almost do. It uses the dispatch style you suggested was goofy, but I think it meets the first two criteria you set forth, and more or less meets the third.
The wrapping class does not have to be modified at all.
It doesn't modify the wrapped class at all.
It only changes the syntax by introducing a dispatch function.
The basic idea is to create a template class, whose parameter is the class of the object to be wrapped, with a template dispatch method, whose parameters are the argument and return types of a member function. The dispatch method looks up the passed in member function pointer to see if it has been called before. If so, it retrieves the record of previous method arguments and calculated results to return the previously calculated value for the argument given to dispatch, or to calculate it if it is new.
Since what this wrapping class does is also called memoization, I've elected to call the template Memo because that is shorter to type than CacheWrapper and I'm starting to prefer shorter names in my old age.
#include <algorithm>
#include <map>
#include <utility>
#include <vector>
// An anonymous namespace to hold a search predicate definition. Users of
// Memo don't need to know this implementation detail, so I keep it
// anonymous. I use a predicate to search a vector of pairs instead of a
// simple map because a map requires that operator< be defined for its key
// type, and operator< isn't defined for member function pointers, but
// operator== is.
namespace {
template <typename Type1, typename Type2>
class FirstEq {
FirstType value;
public:
typedef std::pair<Type1, Type2> ArgType;
FirstEq(Type1 t) : value(t) {}
bool operator()(const ArgType& rhs) const {
return value == rhs.first;
}
};
};
template <typename T>
class Memo {
// Typedef for a member function of T. The C++ standard allows casting a
// member function of a class with one signature to a type of another
// member function of the class with a possibly different signature. You
// aren't guaranteed to be able to call the member function after
// casting, but you can use the pointer for comparisons, which is all we
// need to do.
typedef void (T::*TMemFun)(void);
typedef std::vector< std::pair<TMemFun, void*> > FuncRecords;
T memoized;
FuncRecords funcCalls;
public:
Memo(T t) : memoized(t) {}
template <typename ReturnType, typename ArgType>
ReturnType dispatch(ReturnType (T::* memFun)(ArgType), ArgType arg) {
typedef std::map<ArgType, ReturnType> Record;
// Look up memFun in the record of previously invoked member
// functions. If this is the first invocation, create a new record.
typename FuncRecords::iterator recIter =
find_if(funcCalls.begin(),
funcCalls.end(),
FirstEq<TMemFun, void*>(
reinterpret_cast<TMemFun>(memFun)));
if (recIter == funcCalls.end()) {
funcCalls.push_back(
std::make_pair(reinterpret_cast<TMemFun>(memFun),
static_cast<void*>(new Record)));
recIter = --funcCalls.end();
}
// Get the record of previous arguments and return values.
// Find the previously calculated value, or calculate it if
// necessary.
Record* rec = static_cast<Record*>(
recIter->second);
typename Record::iterator callIter = rec->lower_bound(arg);
if (callIter == rec->end() || callIter->first != arg) {
callIter = rec->insert(callIter,
std::make_pair(arg,
(memoized.*memFun)(arg)));
}
return callIter->second;
}
};
Here is a simple test showing its use:
#include <iostream>
#include <sstream>
#include "Memo.h"
using namespace std;
struct C {
int three(int x) {
cout << "Called three(" << x << ")" << endl;
return 3;
}
double square(float x) {
cout << "Called square(" << x << ")" << endl;
return x * x;
}
};
int main(void) {
C c;
Memo<C> m(c);
cout << m.dispatch(&C::three, 1) << endl;
cout << m.dispatch(&C::three, 2) << endl;
cout << m.dispatch(&C::three, 1) << endl;
cout << m.dispatch(&C::three, 2) << endl;
cout << m.dispatch(&C::square, 2.3f) << endl;
cout << m.dispatch(&C::square, 2.3f) << endl;
return 0;
}
Which produces the following output on my system (MacOS 10.4.11 using g++ 4.0.1):
Called three(1)
3
Called three(2)
3
3
3
Called square(2.3)
5.29
5.29
NOTES
This only works for methods which take 1 argument and return a result. It doesn't work for methods which take 0 arguments, or 2, or 3, or more arguments. This shouldn't be a big problem, though. You can implement overloaded versions of dispatch which take different numbers of arguments up to some reasonable max. This is what the Boost Tuple library does. They implement tuples of up to 10 elements and assume most programmers don't need more than that.
The possibility of implementing multiple overloads for dispatch is why I used the FirstEq predicate template with the find_if algorithm instead of a simple for loop search. It is a little more code for a single use, but if you are going to do a similar search multiple times, it ends up being less code overall and less chance to get one of the loops subtlely wrong.
It doesn't work for methods returning nothing, i.e. void, but if the method doesn't return anything, then you don't need to cache the result!
It doesn't work for template member functions of the wrapped class because you need to pass an actual member function pointer to dispatch, and an un-instantiated template function doesn't have a pointer (yet). There may be a way around this, but I haven't tried much yet.
I haven't done much testing of this yet, so it may have some subtle (or not-so-subtle) problems.
I don't think a completely seamless solution which satisfies all your requirements with no change in syntax at all is possible in C++. (though I'd love to be proven wrong!) Hopefully this is close enough.
When I researched this answer, I got a lot of help from this very extensive write up on implementing member function delegates in C++. Anyone who wants to learn way more than they realized was possible to know about member function pointers should give that article a good read.
I don't think this can be easily done using just a wrapper as you'll have to intercept the IO calls, so wrapping a class would put the code at the wrong layer. In essence, you want to substitute the IO code underneath the object, but you're trying to do it from the top layer. If you're thinking of the code as an onion, you're trying to modify the outer skin in order to affect something two or three layers in; IMHO that suggests the design might need a rethink.
If the class that you're trying to wrap/modify this way does allow you to pass in the stream (or whatever IO mechanism you use), then substituting that one for a caching one would be the right thing to do; in essence that would be what you'd be trying to achieve with your wrapper as well.
It looks like a simple task, assuming the "NumberCruncher" has a known interface, let's say int operator(int).
Note that you'll need to make it more complicated to support other interfaces. In order to do so, i'm adding another template parameter, an Adaptor. Adaptor should convert some interface to a known interface. Here's simple and dumb implementation with static method, which is one way to do it. Also look what Functor is.
struct Adaptor1 {
static int invoke(Cached1 & c, int input) {
return(c.foo1(input));
}
};
struct Adaptor2 {
static int invoke(Cached2 & c, int input) {
return(c.foo2(input));
}
};
template class CacheWrapper<typename T, typeneame Adaptor>
{
private:
T m_cachedObj;
std::map<int, int> m_cache;
public:
// add c'tor here
int calculate(int input) {
std::map<int, int>::const_iterator it = m_cache.find(input);
if (it != m_cache.end()) {
return(it->second);
}
int res = Adaptor::invoke(m_cachedObj, input);
m_cache[input] = res;
return(res);
}
};
I think what you need is something like a proxy / decorator (design patterns). You can use templates if you don't need the dynamic part of those patterns. The point is that you need to well define the interface that you will need.
I haven't figured out the case for handling object methods, but I think I've got a good fix for regular functions
template <typename input_t, typename output_t>
class CacheWrapper
{
public:
CacheWrapper (boost::function<output_t (input_t)> f)
: _func(f)
{}
output_t operator() (const input_t& in)
{
if (in != input_)
{
input_ = in;
output_ = _func(in);
}
return output_;
}
private:
boost::function<output_t (input_t)> _func;
input_t input_;
output_t output_;
};
Which would be used as follows:
#include <iostream>
#include "CacheWrapper.h"
double squareit(double x)
{
std::cout << "computing" << std::endl;
return x*x;
}
int main (int argc, char** argv)
{
CacheWrapper<double,double> cached_squareit(squareit);
for (int i=0; i<10; i++)
{
std::cout << cached_squareit (10) << std::endl;
}
}
Any tips on how to get this to work for objects?