I'm creating my own RDBMS to practice C++. I came up with a solution where each column can have a type and is a template. This is what a row looks like, but it doesn't work
template <typename... col_types>
struct row {
row(std::tuple<std::function<bool(col_types)>, bool, col_types>...col_data){
int i = 0;
([&]{
columns[i] = std::make_unique<column_impl<decltype(std::get<2>(col_data))>>(std::get<0>(col_data), std::get<1>(col_data), std::get<2>(col_data));
i++;
}(), ...);
}
std::array<std::unique_ptr<column_impl<col_types>>, sizeof...(col_types)> columns;
};
And here is a column_impl
template <typename data_t>
struct column_impl {
column_impl<data_t>() {}
column_impl<data_t>(std::function<bool(data_t)> _constraint) : constraint(_constraint) {}
column_impl<data_t>(std::function<bool(data_t)> _constraint, bool _is_nullable)
: constraint(_constraint), is_nullable(_is_nullable) {}
// This constructor requires to validate whether provided data
// satisfies provided constraint. If constraint isn't satisfied
// an exception gets thrown. It needs to be handled
column_impl<data_t>(std::function<bool(data_t)> _constraint, bool _is_nullable, data_t _value)
: constraint(_constraint), is_nullable(_is_nullable) {
if (validate_data()) {
value = _value;
} else {
throw std::invalid_argument("Provived data couldn't satisfy column's constraint");
}
}
std::function<bool(data_t)> constraint = [](data_t) { return true; };
bool is_nullable = false;
data_t value;
auto get_column_type_variant() { return std::variant<data_t>(); }
bool validate_data() { return constraint(value); }
template <typename T>
bool validate_type(T) {
return std::is_nothrow_convertible<T, data_t>();
}
};
Any ideas how to create a container for columns inside of a row and create a constructor that unpacks tuples into a row? I can't get it working. I know this array is not supposed to work, but I have no idea how to write it better. And also I don't want a vector. I could write a polymorphic wrapper like
struct column{some_type_containing_column_impls column_obj;},
but I have no idea how to do it.
And how to properly unpack those tuples into column_impl obj?
Using only non-type template arguments can do the thing.
template<class T>
bool default_constraint(T) {
return true;
}
template<class T, bool nullable = true, bool(constraint)(T) = default_constraint>
class column {
T data;
bool is_null;
public:
column() : data(), is_null(true) { ///< T must be DefaultConstructable
if (!validate())
throw std::invalid_argument("Provided data couldn't satisfy column's constraint");
}
column(T data) : data(data), is_null(false) {
if (!validate())
throw std::invalid_argument("Provided data couldn't satisfy column's constraint");
}
bool validate() {
return nullable || is_null || constraint(data);
}
T get() {
return data;
}
};
template<class... C>
struct row {
std::tuple<C...> columns;
row(C&&... c) : columns(std::forward<C>(c)...) {}
template<int index>
auto get() {
return std::get<index>(columns).get();
}
};
bool require_positive(int i) {
return i >= 0;
}
int main() {
typedef row<column<int>, column<float>, column<bool>> MyRow;
MyRow r{1, 2.3f, true};
using MyRow2 = row<column<int, false, require_positive>, column<float>>;
MyRow2 r2{-1, 2.5}; ///< exception thrown
}
I know maybe you only want the "idea" of how to implement, but I just post the code here for clarity.
Related
I have a template class, ComponentCache, that is essentially a wrapper around a std::vector, except that it only provides random access to the data.
template<class T>
class ComponentCache
{
public:
ComponentCache()
{
m_Components.reserve(1024);
}
~ComponentCache()
{ }
//Get a component stored at some index.
//If the index is greater than the size of the index,
//resize it to the size of the index + 128
T& GetComponent(const std::uint32_t& index)
{
if(index >= m_Components.size())
{
std::uint32_t newSize = index + 128;
m_Components.resize(newSize);
}
return m_Components.at(index);
}
private:
std::vector<T> m_Components;
};
I have another template class, ComponentStorage, that is essentially a wrapper around an std::tuple>.
template<class... T>
class ComponentStorage
{
public:
ComponentStorage()
{ }
~ComponentStorage()
{ }
//Gets a component at some index from the tuple of components
template<class Component>
Component& GetComponent(const aecs::Entity& index)
{
return std::get<aecs::Component::ComponentCache<Component>>
(m_ComponentLines).GetComponent(index);
}
private:
std::tuple<aecs::Component::ComponentCache<T>...> m_ComponentLines;
};
Finally, I have another template class, World, that acts as a place to keep a memory pool and the ComponentStorage class logically near eachother.
template<class... Components>
class World
{
struct EntityMetadata
{
std::bitset<sizeof...(Components)> ComponentBitset;
bool IsActive = false;
};
public:
World(std::size_t size = 128)
{
m_EntityMetadata.resize(size);
}
~World()
{ }
/*Entity Management*/
const aecs::Entity& CreateEntity()
{
auto entity = m_EntityPool.Create();
if(entity != 0xFFFFFFFF)
{
auto entityIndex = aecs::GetIndexFromEntity(entity);
m_EntityMetadata.at(entityIndex).IsActive = true;
}
return std::move(entity);
}
void DestroyEntity(const aecs::Entity& entity)
{
if(entity == 0xFFFFFFFF)
{
return;
}
auto entityIndex = aecs::GetIndexFromEntity(entity);
m_EntityMetadata.at(entityIndex).IsActive = false;
m_EntityPool.Destroy(entity);
}
const std::vector<aecs::Entity>& GetActiveEntities()
{
return m_EntityPool.GetActiveEntities();
}
const bool IsEntityActive(const aecs::Entity& entity)
{
auto entityIndex = aecs::GetIndexFromEntity(entity);
return m_EntityMetadata.at(entityIndex).IsActive;
}
/*Component Management*/
template<class Component>
Component& GetComponentFromEntity(const aecs::Entity &entity)
{
const std::uint32_t index = aecs::GetIndexFromEntity(entity);
return m_ComponentStorage.GetComponent<Component>(index);
}
template<class Component>
void AddComponentToEntity(const aecs::Entity& entity)
{
//TODO: Implement
auto entityIndex = aecs::GetIndexFromEntity(entity);
m_EntityMetadata.at(entityIndex).ComponentBitset.set(
aecs::mpl::IndexOf<Component, std::tuple<Components...>>::value);
}
template<class Component>
void RemoveComponentFromEntity(const aecs::Entity& entity)
{
//TODO: Implement
auto componentIndex = aecs::mpl::IndexOf<Component,
std::tuple<Components...>>::value;
auto entityIndex = aecs::GetIndexFromEntity(entity);
m_EntityMetadata.at(entityIndex).ComponentBitset.reset(componentIndex);
}
template<class Component>
const bool EntityHasComponent(const aecs::Entity& entity)
{
auto componentIndex = aecs::mpl::IndexOf<Component,
std::tuple<Components...>>::value;
auto entityIndex = aecs::GetIndexFromEntity(entity);
std::bitset<sizeof...(Components)> tempBitset;
tempBitset.set(componentIndex);
return (m_EntityMetadata.at(entityIndex).ComponentBitset & tempBitset) ==
tempBitset;
}
private:
aecs::EntityPool m_EntityPool;
aecs::ComponentStorage<Components...> m_ComponentStorage;
std::vector<EntityMetadata> m_EntityMetadata;
};
Throwing it all together, it should work something like this:
struct Position
{
float x;
float y;
};
struct Velocity
{
float x;
float y;
};
int main() {
aecs::World<Position, Velocity> w;
const auto e = w.CreateEntity();
Velocity& v1 = w.GetComponentFromEntity<Velocity>(e);
return 0;
}
However, I get the following compilation error regarding GetComponentFromEntity:
error: expected primary-expression before '>' token
return m_ComponentStorage.GetComponent<Component>(index);
If I switch it up so that it should automatically deduce the type of Component, I instead get the following errors:
E:\CLion\AECS\aecs/World/World.h: In instantiation of 'Component& aecs::World<Components>::GetComponentFromEntity(const Entity&) [with Component = Velocity; Components = {Position, Velocity}; aecs::Entity = unsigned int]':
E:\CLion\AECS\main.cpp:26:54: required from here
E:\CLion\AECS\aecs/World/World.h:69:49: error: no matching function for call to 'aecs::ComponentStorage<Position, Velocity>::GetComponent(const uint32_t&)'
return m_ComponentStorage.GetComponent(index);
^
In file included from E:\CLion\AECS\aecs/World/World.h:9:0,
from E:\CLion\AECS\main.cpp:2:
e:\clion\aecs\aecs\componentstorage\componentstorage.h:27:14: note: candidate: template<class Component> Component& aecs::ComponentStorage<T>::GetComponent(const Entity&) [with Component = Component; T = {Position, Velocity}]
Component& GetComponent(const aecs::Entity& index)
^
e:\clion\aecs\aecs\componentstorage\componentstorage.h:27:14: note: template argument deduction/substitution failed:
In file included from E:\CLion\AECS\main.cpp:2:0:
E:\CLion\AECS\aecs/World/World.h:69:49: note: couldn't deduce template parameter 'Component'
return m_ComponentStorage.GetComponent(index);
It seems like the compiler should have no problem deducing the type of Component at compile-time, because Component is what's being returned.
I feel like I am making some obvious mistake, but everything looks correct to me. Am I forgetting something important regarding templates?
Put yourself into the shoes of the compiler when it's parsing the line:
return m_ComponentStorage.GetComponent<Component>(index);
The type of m_ComponentStorage depends on Components..., which is unknown when parsing the code. How can you possibly tell what GetComponent is supposed to be?
It could be a template member function, but it could also be a simple member variable. For sanity's sake, compilers are instructed to assume they are dealing with a member variable in that scenario.
You can tell the compiler what it's dealing with using
return m_ComponentStorage.template GetComponent<Component>(index);
I'd like to simplify the code I write in my application that handles mutiple data structure types but with a common header. Given something like this:
enum class MyType {
Foo = 100,
Bar = 200,
};
struct Hdr {
MyType type;
};
struct Foo {
Hdr hdr;
int x;
int y;
int z;
};
struct Bar {
Hdr hdr;
double value;
double ratio;
};
void process(const Foo *ptr)
{
// process Foo here
}
void process(const Bar *ptr)
{
// process Bar here
}
extern void *getData();
int main()
{
const void *pv = getData();
auto pHdr = static_cast<const Hdr *>(pv);
switch (pHdr->type) {
case MyType::Foo: process(static_cast<const Foo *>(pv)); break;
case MyType::Bar: process(static_cast<const Bar *>(pv)); break;
default: throw "Unknown";
}
return 0;
}
Ideally I'd like to replace the switch statement above with something like:
process(multi_cast<pHdr->type>(pv);
I'm perfectly okay with having to write statements like this to get it to work:
template<MyType::Foo>
const Foo *multi_cast(void *p)
{
return static_cast<const Foo *>(p);
}
template<MyType::Bar>
const Bar *multi_cast(void *p)
{
return static_cast<const Bar *>(p);
}
But I cannot write a template where the template parameter is a enum (or an int for that matter)
Have I just looked at this for so long that I cannot see an answer?
Or is there just no other way to do it?
There is just no other way to do it.
As the comments have pointed out, since the type is stored in the header at run-time, you have to have some kind of run-time lookup; no amount of templates or overload resolution can help you since all of that is at compile-time.
You can abstract the lookup as much as you want, but you can only replace the switch statement with another type of lookup, and you can only decrease performance the further you get away from a simple switch/lookup table.
For example, you could start with something like this and go nuts:
#include <iostream>
#include <cassert>
enum class Type {
FOO,
BAR,
NUM_
};
struct Header {
Header(Type t)
: type(t)
{}
Type type;
};
struct Foo {
Foo(int x, int y, int z)
: header(Type::FOO), x(x), y(y), z(z)
{}
Header header;
int x;
int y;
int z;
};
struct Bar {
Bar(double value, double ratio)
: header(Type::BAR), value(value), ratio(ratio)
{}
Header header;
double value;
double ratio;
};
static inline void process(Foo*) {
printf("processing foo...\n");
}
static inline void process(Bar*) {
printf("processing bar...\n");
}
using ProcessFunc = void(*)(void*);
static ProcessFunc typeProcessors[(size_t)Type::NUM_] = {
[](void* p) { process((Foo*)p); },
[](void* p) { process((Bar*)p); },
};
static void process(void* p) {
Type t = ((Header*)p)->type;
assert((size_t)t < (size_t)Type::NUM_ && "Invalid Type.");
typeProcessors[(size_t)t](p);
}
static void* get_foo()
{
static Foo foo(0, 0, 0);
return &foo;
}
static void* get_bar()
{
static Bar bar(0.0, 0.0);
return &bar;
}
int main() {
Foo foo(0, 0, 0);
Bar bar(0.0, 0.0);
process(&foo);
process(&bar);
process(get_foo());
process(get_bar());
return 0;
}
but then you're only getting cute and most likely slower. You might as well just put the switch in process(void*)
If you aren't serializing your data(doubtful), are mostly processing one type at a time, and want an OO solution(I wouldn't), you could return a base type that your types inherit from and add a pure virtual process function like so:
struct Type {
virtual void process() = 0;
virtual ~Type() {}
};
struct Foo : Type {
int x = 0;
int y = 0;
int z = 0;
virtual void process() override {
printf("processing foo...\n");
}
};
struct Bar : Type {
double value = 0.0;
double ratio = 0.0;
virtual void process() override {
printf("processing bar...\n");
}
};
static Type* get_foo() {
static Foo foo;
return &foo;
}
static Type* get_bar() {
static Bar bar;
return &bar;
}
int main() {
Foo foo;
Bar bar;
foo.process();
bar.process();
get_foo()->process();
get_bar()->process();
return 0;
}
I would stick with the switch, but I would keep the values of Type::FOO and Type::BAR the default 0 and 1. If you mess with the values too much, the compiler might decide to implement the switch as a bunch of branches as opposed to a lookup table.
You have two issues:
Converting a runtime value (your "type") into a compile time determined type (with associated behavior).
"Unifying" the possible different types to a single (statically at compile time known) type.
Point 2 is what inheritance together with virtual member functions are for:
struct Thing {
virtual void doStuff() const = 0;
virtual ~Thing() {}
};
struct AThing : Thing {
void doStuff() const override { std::cout << "A"; }
};
struct BThing : Thing {
void doStuff() const override { std::cout << "B"; }
};
Point 1 is usually tackled by creating some kind of "factory" mechanism, and then dispatching based on the runtime value to one of those factories. First, the factories:
Thing * factoryA() { return new AThing(); }
Thing * factoryB() { return new BThing(); }
Thing * factory_failure() { throw 42; }
The "dispatching" (or "choosing the right factory") can be done in different ways, one of those being your switch statement (fast, but clumsy), linear search through some container/array (easy, slow) or by lookup in a map (logarithmic - or constant for hashing based maps).
I chose a (ordered) map, but instead of using std::map (or std::unordered_map) I use a (sorted!) std::array to avoid dynamic memory allocation:
// Our "map" is nothing more but an array of key value pairs.
template <
typename Key,
typename Value,
std::size_t Size>
using cmap = std::array<std::pair<Key,Value>, Size>;
// Long type names make code hard to read.
template <
typename First,
typename... Rest>
using cmap_from =
cmap<typename First::first_type,
typename First::second_type,
sizeof...(Rest) + 1u>;
// Helper function to avoid us having to specify the size
template <
typename First,
typename... Rest>
cmap_from<First, Rest...> make_cmap(First && first,
Rest && ... rest) {
return {std::forward<First>(first), std::forward<Rest>(rest)...};
}
Using std::lower_bound I perform a binary search on this sorted array (ehm "map"):
// Binary search for lower bound, check for equality
template <
typename Key,
typename Value,
std::size_t Size>
Value get_from(cmap<Key,Value,Size> const & map,
Key const & key,
Value alternative) {
assert(std::is_sorted(std::begin(map), std::end(map),
[](auto const & lhs, auto const & rhs) {
return lhs.first < rhs.first; }));
auto const lower = std::lower_bound(std::begin(map), std::end(map),
key,
[](auto const & pair, auto k) {
return pair.first < k; });
if (lower->first == key) {
return lower->second;
} else {
// could also throw or whatever other failure mode
return alternative;
}
}
So that, finally, I can use a static const map to get a factory given some runtime value "type" (or choice, as I named it):
int main() {
int const choices[] = {1, 10, 100};
static auto const map =
make_cmap(std::make_pair(1, factoryA),
std::make_pair(10, factoryB));
try {
for (int choice : choices) {
std::cout << "Processing choice " << choice << ": ";
auto const factory = get_from(map, choice, factory_failure);
Thing * thing = factory();
thing->doStuff();
std::cout << std::endl;
delete thing;
}
} catch (int const & value) {
std::cout << "Caught a " << value
<< " ... wow this is evil!" << std::endl;
}
}
(Live on ideone)
The initialization of that "map" could probably made constexpr.
Of course instead of raw pointers (Thing *) you should use managed pointers (like std::unique_ptr). Further, if you don't want to have your processing (doStuff) as member functions, then just make a single "dispatching" (virtual) member function that calls out to a given function object, passing the own instance (this). With a CRTP base class, you don't need to implement that member function for every one of your types.
You're using something that may be called static (=compile-time) polymorphism. This requires to make such switch statements in order to convert the run-time value pHrd->dtype to one of the compile-time values handles in the case clauses. Something like your
process(multi_cast<pHdr->type>(pv);
is impossible, since pHdr->type is not known at compile time.
If you want to avoid the switch, you can use ordinary dynamic polymorphism and forget about the enum Hdr, but use a abstract base class
struct Base {
virtual void process()=0;
virtual ~Base() {}
};
struct Foo : Base { /* ... */ };
struct Bar : Base { /* ... */ };
Base*ptr = getData();
ptr->process();
We have
enum Enum {A,B,C,D,E,F,G,H, NumEnums};
class Base {};
template <Enum...> class Thing : public Base {};
and the function
Base* create (std::list<Enum>& input);
is to create an object of the type that corresponds to input. For example,
if input = {A,E,C,G,D};, then the output shall be of type Thing<A,E,C,G,D>* (let's forget the sorting here). Now I know input is obtained during run-time, but by doing a search, the output can be obtained fairly quickly. If Thing had only one parameter (i.e. input has size() one), then the simple
template <int N>
Base* createHelper (const std::list<Enum>& input) {
const Enum En = static_cast<Enum>(N);
if (input.front() == En)
return new Thing<En>;
return createHelper<N+1>(input);
}
template <>
Base* createHelper<NumEnums> (const std::list<Enum>&) {
return nullptr;
}
Base* create (const std::list<Enum>& input) {
return createHelper<0>(input);
}
will do. I tried to generalize the above to any size list (the size would have to be determined during run-time through a similar recursion as above, but that should be fairly quick too). But I got totally lost on how. So I tried to examine the structure of the naïve method:
#include <iostream>
#include <list>
#include <type_traits>
#include <typeinfo>
enum Enum {A,B,C,D,E,F,G,H, NumEnums};
class Base {
public:
virtual void print() const = 0;
};
template <Enum...> class Thing : public Base {
virtual void print() const override {std::cout << typeid(*this).name() << '\n';}
};
Base* create (std::list<Enum>& input) {
if (input.front() == A) {
input.pop_front();
if (input.empty())
return new Thing<A>;
else {
if (input.front() == A) {
input.pop_front();
if (input.empty())
return new Thing<A,A>;
else {
// ....
}
}
else if (input.front() == B) {
input.pop_front();
if (input.empty())
return new Thing<A,B>;
else {
// ....
}
}
}
}
else if (input.front() == B) {
// similar
}
// ...
}
int main() {
std::list<Enum> userInput = {A,B};
// Wish to construct an instance of Thing<A,B> (efficiently).
Base* thing = create(userInput);
thing->print(); // Thing<A,B>
}
I figured I could put this in recursive form. But I cannot think of it. I know the one-dimensional case can be generalized, but I need help here. Or perhaps there is a better way to do it altogether? Once it works, it should not take anymore than a fraction of a second for the create function to return, assuming NumEnums is a decent size and the Thing class has just several template arguments, and not hundreds.
Edit: Turns out, there may be a viable solution here:
Create an associate array between your key and a type factory class.
Dynamically allocate any variables you may need from the type factory once you have it selected (preferably using std::unique_ptr).
The end result may end of looking like this:
std::unordered_map<std::string, type_allocator> str_to_type;
str_to_type["a"] = type_allocator(int); //where type_allocator derives the type of the class from the input variable.
auto variable = str_to_type[input].allocate();
For specific size, if you compute a single index, you may dispatch at runtime to the correct compile time function:
template <std::size_t N>
std::unique_ptr<Base> make_thing3()
{
constexpr Enum a2 = Enum(N % NumEnums);
constexpr Enum a1 = Enum((N / NumEnums) % NumEnums);
constexpr Enum a0 = Enum((N / NumEnums / NumEnums) % NumEnums);
return std::make_unique<Thing<a0, a1, a2>>();
}
template <std::size_t... Is>
std::unique_ptr<Base> make_thing3(std::size_t index, std::index_sequence<Is...>)
{
using maker = std::unique_ptr<Base>();
maker* fs[] = {&make_thing3<Is>...};
return fs[index]();
}
std::unique_ptr<Base> make_thing3(const std::array<Enum, 3u>& a)
{
std::size_t index = 0;
for (Enum e : a) {
index *= NumEnums;
index += e;
}
constexpr std::size_t total = NumEnums * NumEnums * NumEnums;
return make_thing3(index, std::make_index_sequence<total>{});
}
Live Demo
Note: I had to change size of Enum, and reduce my example from make_thing5 to make_thing3 due to compiler limit (not sure if it came from the site or if it is true limits)
This solution shows that though the compile-time is long (due to the many template instantiations), the run-time look-up is instant. The compiler limits is 3 enum values as input though. The empty input case is handled too (the return type being Thing<>*).
#include <iostream>
#include <list>
#define show(variable) std::cout << #variable << " = " << variable << std::endl;
enum Enum {A,B,C,D,E,F,G,H, NumEnums};
class Base {
public:
virtual void print() const = 0;
};
template <Enum... Es> class Thing : public Base {
virtual void print() const override {
const std::list<int> a = {((std::cout << Es << ' '), 0)...};
std::cout << "\nPack size = " << sizeof...(Es) << '\n';
}
};
template <int N, int Size, Enum... Es>
struct Create {
static Base* execute (std::list<Enum>& input) {
const Enum En = static_cast<Enum>(N);
if (input.front() == En) {
input.pop_front();
return Create<0, Size-1, Es..., En>::execute(input);
}
return Create<N+1, Size, Es...>::execute(input);
}
};
template <int N, Enum... Es>
struct Create<N, 0, Es...> {
static Base* execute (std::list<Enum>&) {return new Thing<Es...>;}
};
template <int Size, Enum... Es>
struct Create<NumEnums, Size, Es...> {
static Base* execute (std::list<Enum>&) {return nullptr;} // This will never be reached
};
template <int Size>
Base* do_create (std::list<Enum>& input) {
if (input.size() == Size)
return Create<0, Size>::execute(input);
return do_create<Size+1>(input);
}
template <>
Base* do_create<4> (std::list<Enum>&) {
std::cout << "Cannot exceed 3 values.\n";
return nullptr;
}
Base* create (std::list<Enum>& input) {
return do_create<0>(input);
}
int main() {
std::list<Enum> input = {E,A,F};
Base* thing = create(input);
thing->print(); // 4 0 5
input = {};
create(input)->print(); // Pack size = 0.
}
I am trying to create a helper class to abstract invoking function pointers. With feedback from others on SO, I am using a polymorphic class to achieve this (shown below). Templates are also used to reduce code duplication.
typedef void(*PFNFOO1) (int);
typedef void(*PFNFOO2) (double);
typedef void(*PFNBAR1) (long);
typedef void(*PFNBAR2) (float);
typedef struct FOO_TABLE
{
PFNFOO1 pfnFoo1;
PFNFOO2 pfnFoo2;
} FOO_TABLE;
typedef struct BAR_TABLE
{
PFNBAR1 pfnBar1;
PFNBAR2 pfnBar2;
} BAR_TABLE;
enum TABLE_TYPE
{
TYPE_FOO = 0,
TYPE_BAR = 1,
};
template <typename T>
class FooBarImpl : public FooBarBase
{
public:
// GetFunc is created to centralize needed validation before function is invoked
void* GetFunc(size_t funcOffset)
{
// do some validation
return reinterpret_cast<void*>(m_FooBarTable + funcOffset);
}
void* GetpfnFoo1() { return GetFunc(offsetof(T, pfnFoo1)); }
void* GetpfnFoo2() { return GetFunc(offsetof(T, pfnFoo2)); }
void* GetpfnBar1() { return GetFunc(offsetof(T, pfnBar1)); }
void* GetpfnBar2() { return GetFunc(offsetof(T, pfnBar2)); }
T* m_FooBarTable;
};
class FooBarBase
{
public:
static FooBarBase* CreateFooBar(TABLE_TYPE tableType)
{
switch(tableType)
{
case (TYPE_FOO) :
{
return new FooBarImpl<FOO_TABLE>();
}
break;
case (TYPE_BAR) :
{
return new FooBarImpl<BAR_TABLE>();
}
break;
}
}
virtual void* GetpfnFoo1() = 0;
virtual void* GetpfnFoo2() = 0;
virtual void* GetpfnBar1() = 0;
virtual void* GetpfnBar2() = 0;
};
int _tmain(int argc, _TCHAR* argv[])
{
{
FooBarBase *pFooBar = FooBarBase::CreateFooBar(TYPE_FOO);
// Initialize Foo table
auto p = reinterpret_cast<PFNFOO1>(pFooBar->GetpfnFoo1());
int parameter = 1;
p(parameter);
}
{
FooBarBase *pFooBar = FooBarBase::CreateFooBar(TYPE_FOO);
// Initialize Bar table
auto p = reinterpret_cast<PFNBAR2>(pFooBar->GetpfnBar2());
float parameter = 1.0f;
p(parameter);
}
return 0;
}
This is currently giving me complication errors as "C2039: 'pfnBar1' : is not a member of 'FOO_TABLE'" which makes sense because one of the implicit template specialization will try to do "offsetof(FOO_TABLE, pfnBar1)," which isn't allowed. I have two questions. First, I am wondering what's the best way to address this error. I think I can possibly address this by providing explicit template specializations for FooBarImpl and FooBarImpl, but I'd like to avoid doing that because it means that if I were to add a new table type later, I'd have to add another specialization. Also, it increases code duplication. Therefore, if there's a way to fix this issue without explicit template specialization, please let m know.
For my second question, if explicit template specialization cannot be avoided, I have also tried this:
class FooBarBase;
template <typename T>
class FooBarImpl : public FooBarBase
{
};
template <>
class FooBarImpl<FOO_TABLE> : public FooBarBase
{
public:
typedef FOO_TABLE T;
// GetFunc is created to centralize needed validation before function is invoked
void* GetFunc(size_t funcOffset)
{
// do some validation
return reinterpret_cast<void*>(m_FooBarTable + funcOffset);
}
void* GetpfnFoo1() { return GetFunc(offsetof(T, pfnFoo1)); }
void* GetpfnFoo2() { return GetFunc(offsetof(T, pfnFoo2)); }
T* m_FooBarTable;
};
template<>
class FooBarImpl<BAR_TABLE> : public FooBarBase
{
public:
typedef BAR_TABLE T;
// GetFunc is created to centralize needed validation before function is invoked
void* GetFunc(size_t funcOffset)
{
// do some validation
return reinterpret_cast<void*>(m_FooBarTable + funcOffset);
}
void* GetpfnBar1() { return GetFunc(offsetof(T, pfnBar1)); }
void* GetpfnBar2() { return GetFunc(offsetof(T, pfnBar2)); }
T* m_FooBarTable;
};
But for some reason, I keep getting this error "error C2504: 'FooBarBase' : base class undefined" even if it was working fine before I specialized the templates.
If anyone has ideas about these 2 questions, I'd really appreciate your feedback. Thanks.
I want to used Policy Based Design to have the return type of a host class change based on the policies I'm using. Here is an example:
class IntPolicy {
public:
int doIntPolicy(double anInput) {
return static_cast<int>(anInput);
}
};
class DoublePolicy {
public:
double doDoublePolicy(int anInput) {
return static_cast<double>(anInput);
}
};
template<typename IntPolicyType, typename DoublePolicyType>
class SimpleHost {
private:
IntPolicyType _intPolicy;
DoublePolicyType _doublePolicy;
public:
template<typename InputType>
auto doHost(InputType input) -> decltype(_doublePolicy.doDoublePolicy(_intPolicy.doIntPolicy(input))) {
auto aVar = _intPolicy.doIntPolicy(input);
return _doublePolicy.doDoublePolicy(aVar);
}
};
Here is how I'd use the host class and policies:
typedef SimpleHost<IntPolicy, DoublePolicy> Host;
Host host;
auto theOutput = host.doHost(5);
While this compiles and works, notice that I must essentially put the body of the doHost method inside the decltype function so that the compiler can deduce the trailing return. If the body of the doHost function was large then this would look incredibly ugly. Is there any way I can avoid this?
If you don't like how it looks then probably try define?
#define RECURSE_POLICY(E) policy2.doPolicy(policy1.doPolicy(E))
template<typename InputType>
auto doHost(InputType input) -> decltype(RECURSE_POLICY(input)) {
return RECURSE_POLICY(input);
}
Having said that, something doesn't look right that you have to call doPolicy twice. Maybe you can refactor it out.
1.- Extending the template
#include <stdio.h>
#include <string>
#include <iostream>
class IntPolicy {
public:
int doIntPolicy(double anInput=NULL) {
if(!NULL)
{
return static_cast<int>(anInput);
}
else
{
return -1;
}
}
};
class DoublePolicy {
public:
double doDoublePolicy(int anInput=NULL) {
if(!NULL)
{
return static_cast<double>(anInput);
}
else
{
return -1;
}
}
};
template<typename IntPolicyType, typename DoublePolicyType,
class __Type >
class SimpleHost {
private:
IntPolicyType _intPolicy;
DoublePolicyType _doublePolicy;
public:
template<typename InputType>
auto doHost(InputType input) -> __Type {
auto aVar = _intPolicy.doIntPolicy(input);
return _doublePolicy.doDoublePolicy(aVar);
}
};
int main()
{
IntPolicy foo;
DoublePolicy bar;
typedef SimpleHost<IntPolicy, DoublePolicy,
decltype(bar.doDoublePolicy(foo.doIntPolicy()))> Host;
Host host;
auto theOutput = host.doHost(5);
return 0;
}
2.- The simplest way would be to rename the impl, if you are using an external library you could consider Wrapping it for this purpose
class IntPolicy {
public:
int doPolicy(double anInput) {
return static_cast<int>(anInput);
}
};
class DoublePolicy {
public:
double doPolicy(int anInput) {
return static_cast<double>(anInput);
}
};
template<typename IntPolicyType, typename DoublePolicyType>
class SimpleHost {
private:
IntPolicyType _intPolicy;
DoublePolicyType _doublePolicy;
public:
template<typename InputType>
auto doHost(InputType input) -> decltype(_doublePolicy.doPolicy(_intPolicy.doPolicy(input)))
{
auto aVar = IntPolicyType.doPolicy(input);
return DoublePolicyType.doPolicy(aVar);
}
But to really help you, we need the specific functions you are trying to call, I mean I feel like this is a mess already.