Order independant variadic template arguments - c++

I want to create a system of "Mapper", i.e objects that takes an input (template) value and return a output (template) value. A mapper can have additional features / traits.
Sample code :
// a trait
template <typename I, typename O>
class Writable
{
public:
virtual ~Writable() = default;
virtual O & operator()(I i) = 0;
};
// another trait
template <typename I, typename O>
class Bounded
{
public:
virtual ~Bounded() = default;
virtual O min() const = 0;
virtual O max() const = 0;
};
// base class
template <typename I, typename O, template<typename, typename> class ... Traits>
class IMap
: public Traits<I, O>...
{
public:
virtual ~IMap() = default;
virtual O operator()(I i) const = 0;
};
// a test mapper
class Test1
: public IMap<int, double, Writable, Bounded>
{
public:
double operator()(int i) const override { return _d; }
double & operator()(int i) override { return _d; }
double min() const override { return 0; }
double max() const override { return 1; }
private:
double _d;
};
// another test mapper
class Test2
: public IMap<int, double, Bounded, Writable>
{
public:
double operator()(int i) const override { return _d; }
double & operator()(int i) override { return _d; }
double min() const override { return 0; }
double max() const override { return 1; }
private:
double _d;
};
// a class to use mappers
template <typename I, typename O>
class MapUse
{
public:
// I would like this function to accept an IMap containing "at least" the Bounded trait
// Ideally this function signature should be like
void method_requiring_writable(IMap<I, O, Bounded> & map)
{
map(123)
map(123) = 0;
}
// I would like this function to accept an IMap containing "at least" the Bounded and Writable traits
// (no matter the actual order of those traits in variadic template parameter )
// Ideally this function signature should be like
void method_requiring_bounded_and_writable(IMap<I, O, Bounded, Writable> & map)
{
map(123);
map(123) = 0;
map.min();
}
};
void test()
{
Test1 t1;
Test2 t2;
Test2 * p = dynamic_cast<Test2*>(&t1); // << always return nullptr, of course !
MapUse<int, double> mu;
mu.method_requiring_writable(t1); // << does not compile, not the right type
mu.method_requiring_bounded_and_writable(t1); // << does not compile, not the right type
return;
}
Error at line : mu.method_requiring_writable(t1) :
error C2664: 'void MapUse<int,double>::method_requiring_writable(IMap<I,O,Bounded> &)': cannot convert argument 1 from 'Test1' to 'IMap<I,O,Bounded> &'
> with
> [
> I=int,
> O=double
> ]
Error at line : mu.method_requiring_bounded_and_writable(t1) :
error C2664: 'void MapUse<int,double>::method_requiring_bounded_and_writable(IMap<int,double,Bounded,Writable> &)': cannot convert argument 1 from 'Test1' to 'IMap<int,double,Bounded,Writable> &'
I perfectly understand why this does not work, but I would like a "trick" to make it work !
First problem : Order of traits in variadic template parameter does count. It should easily be solved by forcing the developer to respect traits order, but it's not ideal
Second problem : Be able to create methods that requires a mapped with "at least" a specific set of traits. No clue about this one.
First approach was not variadic, but a - very - complex hierarchy with lots of virtual heritage --> ugly as hell, it's a real pain to add a new trait
With the code above, I thought about adding some kind of cast operators in IMap but failed to do so.
Any C++ / variadic / magic stuff specialist to help on this ?

You can use something like this:
#include <type_traits>
template <template <class, class> class... Traits,
std::enable_if_t<
std::is_base_of<Bounded<I, O>, IMap<I, O, Traits...>>::value
and std::is_base_of<Writable<I, O>, IMap<I, O, Traits...>>::value
, int> = 0>
void method_requiring_bounded_and_writable(IMap<I, O, Traits...> & map) {
// Do stuff
}

Why do you wan't to check the mixed-in types in the first place? You are mixing generic and non-generic programming here. Simply use the implemented traits (like min() and max()) and forget about how they were implemented. A straight-forward and clean solution is to simply continue using generic programming:
//template <typename I, typename O>
class MapUse {
public:
template <typename T>
void method_requiring_writable(T& map) {
map(123);
map(123) = 0;
}
template <typename T>
void method_requiring_bounded_and_writable(T& map) {
map(123);
map(123) = 0;
map.min();
}
};
Other solutions require heavy meta-programming and only make your code more complex and hard to read. I understand that this might not solve your very specific problem. This is an advise to rethink your design and fully jump on the generic train or drop it altogether.

Related

Variadic template class implicitly converting

I have a class and need to validate that it's function calls are being called w/ the right parameters. The function signature is always the same (sans 1 argument type). So, naturally I went for a templated approach. So generally the validation policy would have a template parameter per data type it could handle:
using P = Policy<int, double, UserDefined>
Or something of that ilk.
I got it to compile, but the caveat is that if double and int (or anything a double can convert to actually) are both template parameters, the double will be implicitly converted.
The policy looks like this:
template <typename... T>
class BasicValidationPolicy { };
template <>
class BasicValidationPolicy<>
{
public:
void RegisterSetHandler();
};
template <typename T, typename... Rest>
class BasicValidationPolicy<T, Rest...> : public BasicValidationPolicy<Rest...>
{
public:
using SetHandler = std::function<void(int, T)>;
void RegisterSetHandler(const SetHandler& handler)
{
m_setHandler = handler;
}
void Set(int n, const T& val) {
if (m_setHandler) {
m_setHandler(n, val);
}
}
private:
SetHandler m_setHandler{nullptr};
};
The class that uses it...
template <typename ValidatorPolicy>
class MyClass : public ValidatorPolicy {
public:
void OnSetInt(int n, int64_t v)
{
ValidatorPolicy::Set(n, v);
}
void OnSetDouble(int n, double d)
{
ValidatorPolicy::Set(n, d);
}
};
Usage:
int main()
{
using Policy = BasicValidationPolicy<int64_t, double>; // doesn't work
MyClass<Policy> m;
m.Policy::RegisterSetHandler([](int i, double value) {
// by this point value is an int64_t
std::cout << "Got double " << i << ", " << value << "\n";
});
double d{35.2135};
m.OnSetDouble(1, d);
}
To boot, doing this does work
using Policy = BasicValidationPolicy<double, int64_t>;
So I guess I'm missing something about the template deduction. Looks like it tries to match double against std::int64_t says "meh, good enough", and moves on. Nice to know a way around it (kind of) but that looks like it would be very tricky to maintain.
It's complicated...
First of all: you have a recursive template class, BasicValidationPolicy, where you define two methods and you want that all methods, for all recursion steps of the class, are available.
Unfortunately, the definition of the methods in the derived classes hide the method in base classes.
To un-hide the inherited methods, you have to explicitly add a pair of using
using BasicValidationPolicy<Rest...>::Set;
using BasicValidationPolicy<Rest...>::RegisterSetHandler;
At this point, the code doesn't compile because you need a Set() and a RegisterSetHandler() in the ground case class. You have declared a dummy RegisterSetHandler() but not a dummy Set(). You have to add one, so the ground case become
template <>
class BasicValidationPolicy<>
{
public:
void RegisterSetHandler();
void Set();
};
Now your MyClass<Policy> object expose two RegisterSetHandler() methods (before only one): one receiving a std::function<void(int, std::int64_t)>, the other (before hidden) receiving a std::function<void(int, double)>.
But when you pass a lambda, you have a chicken-and-egg problem: the lambda can be converted to a std::function but isn't a std::function. So can't be used to deduce the template parameters of std::function because the types are to be known before to deduce them.
A possible solution is impose a lambda/std::function conversion in the call
// ..........................VVVVVVVVVVVVVV
m.Policy::RegisterSetHandler(std::function{[](int i, double value) {
// by this point value is an int64_t
std::cout << "Got double " << i << ", " << value << "\n";
}});
// ...........................^
using also the template deduction guides introduced in C++17.
So your code become
#include <iostream>
#include <functional>
template <typename... T>
class BasicValidationPolicy { };
template <>
class BasicValidationPolicy<>
{
public:
void RegisterSetHandler();
void Set();
};
template <typename T, typename... Rest>
class BasicValidationPolicy<T, Rest...> : public BasicValidationPolicy<Rest...>
{
public:
using SetHandler = std::function<void(int, T)>;
using BasicValidationPolicy<Rest...>::Set;
using BasicValidationPolicy<Rest...>::RegisterSetHandler;
void RegisterSetHandler(const SetHandler& handler)
{
m_setHandler = handler;
}
void Set(int n, const T& val) {
if (m_setHandler) {
m_setHandler(n, val);
}
}
private:
SetHandler m_setHandler{nullptr};
};
template <typename ValidatorPolicy>
class MyClass : public ValidatorPolicy {
public:
void OnSetInt(int n, int64_t v)
{
ValidatorPolicy::Set(n, v);
}
void OnSetDouble(int n, double d)
{
ValidatorPolicy::Set(n, d);
}
};
int main ()
{
using Policy = BasicValidationPolicy<int64_t, double>; // doesn't work
MyClass<Policy> m;
m.Policy::RegisterSetHandler(std::function{[](int i, double value) {
std::cout << "Got double " << i << ", " << value << "\n";
}});
double d{35.2135};
m.OnSetDouble(1, d);
}
There's a small alternative to the recursive definition that might be easier to work with...
template<typename T>
class ValidationPolicy {
// Set/Register/etc
};
template <typename... Ts>
class BasicValidationPolicy : public ValidationPolicy<Ts>... {
public:
using ValidationPolicy<Ts>::Set...;
using ValidationPolicy<Ts>::RegisterSetHandler...;
};
This can have some impacts on compile time and other aspects of development, though most likely relatively minor. For instance, if you have dozens of classes used in hundreds of different policy combinations in your app, the recursive definition will lead to many more distinct types and larger binaries to support that. For example, in the recursive definition BasicValidationPolicy<T1, T2, T3> and BasicValidationPolicy<T3, T2, T1> being used would generate 7 distinct types in a hierarchy (the empty one is shared in both expansions). The same thing in the flatter hierarchy would be 5 distinct types - one for each of T1, T2, T3 and one for each combination. Adding in BasicValidationPolicy<T2, T3, T1> would add 3 more types recursively but 1 more type in the flat form.
The answer from #max66 isn't wrong, just something else to think about.

Expression templates with a hierarchy defined on the nodes in the syntax tree

I found an excellent explanation of expression templates here. In the article, we find a basic expression template implementation for arithmetic, as follows (slightly adapted):
#include <iostream>
template <typename T>
struct plus {
T operator()(const T a, const T b) const { return a + b; }
};
template <class ExprT>
struct exprTraits {
typedef ExprT expr_type;
};
template <class ExprT1, class ExprT2, class BinOp>
class BinaryExpr {
public:
BinaryExpr(ExprT1 e1, ExprT2 e2, BinOp op = BinOp()) : _expr1(e1), _expr2(e2), _op(op) {}
double eval() const { return _op(_expr1.eval(), _expr2.eval()); }
private:
typename exprTraits<ExprT1>::expr_type _expr1;
typename exprTraits<ExprT2>::expr_type _expr2;
BinOp _op;
};
class Literal {
public:
Literal(const double v) : _val(v) {}
double eval() const { return _val; }
private:
const double _val;
};
template <>
struct exprTraits<double> {
typedef Literal expr_type;
};
class Variable {
public:
Variable(double& v) : _val(v) {}
double eval() const { return _val; }
void operator+=(double x) { _val += x; }
private:
double& _val;
};
class SpecialVariable : public Variable {
public:
SpecialVariable(double& v) : Variable{v} {};
double eval() const { return -1000.0; }
};
template <class ExprT1, class ExprT2>
BinaryExpr<ExprT1, ExprT2, plus<double>> operator+(ExprT1 e1, ExprT2 e2) {
return BinaryExpr<ExprT1, ExprT2, plus<double>>(e1, e2);
}
There are three type of nodes, Literal, Variable and SpecialVariable which is a subclass of the latter. The traits are there to allow for built-in types like double in the expressions without wrapping them with Literal.
Now, suppose I want to do something particular when I add a double and a Variable and plus-assign it to a Variable. I add following member function to Variable:
void operator+=(BinaryExpr<double, Variable, plus<double>> expr) { _val += 1000.0; }
and write a little test program:
int main(int argc, char const* argv[]) {
double xd = 2.0, yd = 5.0;
Variable x{xd};
SpecialVariable y{yd};
x += 3.0 + y;
std::cout << "result : " << std::to_string(x.eval()) << "\n";
return 0;
}
This, however, only works with Variables and not SpecialVariables, i.e. I get following compiler error:
error: no match for ‘operator+=’ (operand types are ‘Variable’ and ‘BinaryExpr<double, SpecialVariable, plus<double> >’) x += 3.0 + y;
note: no known conversion for argument 1 from ‘BinaryExpr<double, SpecialVariable, plus<double> >’ to ‘BinaryExpr<double, Variable, plus<double> >’
which is completely reasonable since template classes do not necessarily have a relation if their template arguments have one.
Question: how can I write one operator+= that accepts expression templates with types and possibly their subtypes? I've not seen an expression template tutorial that addresses this particular problem.
Question: how can I write one operator+= that accepts expression templates with types and possibly their subtypes?
Using std::is_base_of and SFINAE
template <typename V>
std::enable_if_t<std::is_base_of_v<Variable, V>>
operator+= (BinaryExpr<double, V, plus<double>> expr)
{ _val += 1000.0; }
The preceding code compile in C++17.
If you're using C++14 you have to use
std::is_base_of<Variable, V>::value
instead of
std::is_base_of_v<Variable, V>
If you're using C++11 you have to use
typename std::enable_if<std::is_base_of<Variable, V>::value>::type
instead of
std::enable_if_t<std::is_base_of_v<Variable, V>>

Abstraction over single c++ object and std::pair of objects using templates

Assume the following template construction:
enum class ENUM {SINGLE, PAIR};
// General data type
template<ENUM T, class U>class Data;
// Partially specialized for single objects
template<class U>Data<ENUM::SINGLE, U> : public U {
// Forward Constructors, ...
};
// Partially specialized for pairs of objects
template<class U>Data<ENUM::PAIR, U> : public std::pair<U,U> {
// Forward Constructors, ...
};
In my code I want to be able to write something like
template<ENUM T>someMethod(Data<T, SomeClass> data) {
for_single_or_pair {
/*
* Use data as if it would be of type SomeClass
*/
}
}
which should do the same as the combination of the following methods:
template<>someMethod(Data<ENUM::SINGLE, SomeClass> data) {
data.doStuff();
}
template<>incrementData(Data<ENUM::PAIR, SomeClass> data) {
data.first.doStuff();
data.second.doStuff();
}
I.e. I want to be able to use a pair of objects (of the same type) as if it would be a single object. Of course I could reimplement the methods of a type T for Data<ENUM::PAIR, T> (see the answer of dau_sama) which for the given example would look like:
template<>Data<ENUM::PAIR, SomeClass> : public std::pair<SomeClass, SomeClass> {
doStuff() {
this->first.doStuff();
this->second.doStuff();
}
};
But I would have to do this for many methods and operators and many different types, although the methods and operators would all look like this example.
The syntax of the solution may be very different from what I wrote above, this is just to demonstrate what I want to achieve. I would prefer a solution without macros, but could also live with that.
Can such an abstraction be realized in C++11?
The reasons I want to do this are
I do not have to specialize templated methods that shall work for ENUM::Single and ENUM::PAIR when all differences between the specializations would math the pattern above (avoid a lot of code duplication).
The same pattern is occuring very often in my code and I could avoid implementing workarounds in many places, which would be almost identical in each case.
You could try to create a template method applyMethod. Here is a complete example. I used an Executor class containing only one static method because I could not find a better way to process methods taking any types of parameters
#include <iostream>
#include <string>
enum ENUM {SINGLE, PAIR};
// General data type
template<ENUM T, class U>class Data {
};
// Partially specialized for single objects
template<class U>
class UData : public Data<ENUM::SINGLE, U>, public U {
// Forward Constructors, ...
public:
UData(const U& u): U(u) {};
};
// Partially specialized for pairs of objects
template<class U>
class PData : public Data<ENUM::PAIR, U>, public std::pair<U,U> {
// Forward Constructors, ...
public:
PData(const U& u1, const U& u2): std::pair<U, U>(u1, u2) {};
};
template <class U, typename... P>
class Executor {
Executor() = delete;
public:
template<void (U::*M)(P... params)>
static void applyMethod(Data<ENUM::SINGLE, U> &data, P ...params) {
UData<U>& ud= reinterpret_cast<UData<U>& >(data);
U& u = static_cast<U&>(ud);
(u.*M)(params...);
}
template<void (U::*M)(P... params)>
static void applyMethod(Data<ENUM::PAIR, U> &data, P ...params) {
PData<U>& pd = reinterpret_cast<PData<U>& >(data);
(pd.first.*M)(params...);
(pd.second.*M)(params...);
}
};
class X {
std::string name;
public:
X(const std::string& name): name(name) { };
void doStuff(void) {
std::cout << "DoStuff : " << name << std::endl;
}
void doStuff(int i) {
std::cout << "DoStuff : " << name << " - " << i << std::endl;
}
};
int main() {
X x1("x1");
X x2("x2");
X x3("x3");
UData<X> data1(x1);
PData<X> data2(x2, x3);
Executor<X>::applyMethod<&X::doStuff>(data1);
Executor<X, int>::applyMethod<&X::doStuff>(data2, 12);
return 0;
}
You could add a common method to your classes
template<class U>
Data<ENUM::SINGLE, U> : public U {
// Forward Constructors, ...
void handle() {
//do some specific handling for this type
return;
}
};
Now someMethod will just call the right "handle" and it'll automatically switch between the two
template<typename T>
someMethod(T& data) {
data.handle();
}
//If you want to bind your function to some other name, you could
//create a functor that calls someMethod with the arguments passed in _1
//I haven't tested it, there might be some syntax problems with the way you pass in the function name
auto someOtherMethod = std::bind (someMethod, _1);
If your type doesn't implement a handle method, you'll have a nasty compilation error. If you want to provide a default implementation and avoid a compilation error, there is a common pattern called SFINAE (Substitution failure is not an error) that does exactly that.
Here's an alternative to the solution to that from Serge Ballesta, using lambdas.
#include <functional>
template<ENUM T, class U>void for_single_or_pair(
Data<T, U>& data,
std::function<void(U&)> function);
template<class U>void for_single_or_pair(
Data<ENUM::SINGLE, U>& data,
std::function<void(U&)> function) {
function(data);
}
template<class U>void for_single_or_pair(
Data<ENUM::PAIR, U>& data,
std::function<void(U&)> function) {
function(data.first);
function(data.second);
}
Usage:
template<ENUM T>someMethod(Data<T, SomeClass> data) {
for_single_or_pair(data,[](SomeClass& someObject) {
// Play around with someObject in any way
});
}
In this way additionally to use member methods of SomeClass, the data can be used in any other way.
I would be happy about comments to this solution (and if it could be generalized to use more than one Data inside the for_single_or_pair method).

How to generalise this further using (variadic) templates

I am having trouble going the second step or level in templating my code. I have stripped the code to its bare essentials for readability.
I have looked through a lot of templates questions, but I was not really able to solve my exact issue.
I currently have a class RIVRecord, which I templated like this
template <class T>
class RIVRecord
{
private:
std::vector<T> values;
public:
std::string name;
RIVRecord(std::string _name, std::vector<T> _values) { name = _name; values = _values; };
~RIVRecord(void) { };
size_t size() {
return values.size();
}
T* Value(int index) {
return &values[index];
}
}
Easy enough. The T types are usually primitive types such as floats and integers. Then I want to put these RIVRecords in a DataSet class. Here is where I am having more difficulty. Untemplated it would be something like this:
class RIVDataSet
{
private :
//How to template this??
vector<RIVRecord<float>> float_records;
vector<RIVRecord<int>> int_records;
public:
RIVDataSet(void);
~RIVDataSet(void);
//And this
void AddRecord(RIVRecord<float> record) {
//How would this work?
}
//And this?
RIVRecord<float> GetFloatRecord();
};
I come from a Java background, so there I could use the vector<?> and do type checking whenever I ask a RIVRecord. But this does not seem possible in C++. I tried using variadic templates but am unsure how to construct the vector using all types in the template :
template <class... Ts>
class RIVDataSet
{
private :
//For each T in Ts
vector<RIVRecord<T>> records;
public:
RIVDataSet(void);
~RIVDataSet(void);
//For each T in Ts
void AddRecord(RIVRecord<T> record) {
//How would this work?
}
//For each T in Ts, get the record by index.
RIVRecord<T> GetRecord(int index);
};
I already saw that this sort of iteration in C++ templates is not possible, but it is just to clarify what I would want.
Any help is very welcome, thank you.
EDIT:
There is no restriction on the number of types (floats, ints,...) for T
Also, GetRecord works by having an index, but I don't really care about it that much, as long as I can iterate over the records and get the right type.
Solving this via variadic templates is not very complicated, but requires some additional support types. Let us begin, by looking at the result:
template <typename... V>
class many_vectors
{
static_assert(are_all_different<V...>::value, "All types must be different!");
std::tuple<std::vector<V>...> _data;
public:
template<typename T>
std::vector<T>& data()
{ return std::get<index_of<T, V...>::value>(_data); }
template<typename T>
std::vector<T> const& data() const
{ return std::get<index_of<T, V...>::value>(_data); }
template<typename T>
void push_back(T&& arg)
{ data<typename std::remove_reference<T>::type>().push_back(std::forward<T>(arg)); }
template<typename T, typename... W>
void emplace_back(W&&... args)
{ data<T>().emplace_back(std::forward<W>(args)...); }
};
The static_assert defines a very important requirement: Since we are differentiating on types, we must ensure that all types are different. The _data member is a std::tuple of the vectors for the different types, and corresponds directly to your float_records and int_records members.
As an example of providing a member function that refers to one of the vectors by their type the data function exposes the individual vectors. It uses a helper template to figure out which element of the tuple corresponds to your type and gets the result.
The push_back function of the vectors is also exposed to show how to use that to provide functions on these. Here std::forward is used to implement perfect forwarding on the argument to provide optimal performance. However, using rvalue references in combination with templates parameter deduction can lead to slightly unexpected results. Therefore, any reference on the T parameter is removed, so this push_back will not work for a many_vectors containing reference types. This could be fixed by instead providing two overloads push_back<T>(T&) and push_back<T>(T const&).
Finally, the emplace_back exposes a function that cannot rely on template parameter argument deduction to figure out which vector it is supposed to utilize. By keeping the T template parameter first, we allow a usage scenario in which only T is explicitly specified.
Using this, you should be ably to implement arbitrary additional members with similar funcitonality (e.g. begin<T> and end<T>).
Helpers
The most important helper is very simple:
template<typename T, typename U, typename... V>
struct index_of : std::integral_constant<size_t, 1 + index_of<T, V...>::value>
{ };
template<typename T, typename... V>
struct index_of<T, T, V...> : std::integral_constant<size_t, 0>
{ };
This will fail with a fairly ugly error message, if the first argument is not one of the following at all, so you may wish to improve on that.
The other helper is not much more complicated:
template<typename T, typename... V>
struct is_different_than_all : std::integral_constant<bool, true>
{ };
template<typename T, typename U, typename... V>
struct is_different_than_all<T, U, V...>
: std::integral_constant<bool, !std::is_same<T, U>::value && is_different_than_all<T, V...>::value>
{ };
template<typename... V>
struct are_all_different : std::integral_constant<bool, true>
{ };
template<typename T, typename... V>
struct are_all_different<T, V...>
: std::integral_constant<bool, is_different_than_all<T, V...>::value && are_all_different<V...>::value>
{ };
Usage
Yes, usage is as simple as you might hope:
v.push_back(int(3));
v.push_back<float>(4);
v.push_back<float>(5);
v.push_back(std::make_pair('a', 'b'));
v.emplace_back<std::pair<char, char>>('c', 'd');
std::cout << "ints:\n";
for(auto i : v.data<int>()) std::cout << i << "\n";
std::cout << "\n" "floats:\n";
for(auto i : v.data<float>()) std::cout << i << "\n";
std::cout << "\n" "char pairs:\n";
for(auto i : v.data<std::pair<char, char>>()) std::cout << i.first << i.second << "\n";
With the expected result:
ints:
3
floats:
4
5
char pairs:
ab
cd
You can use a technique called type erasure, you'll have to include another level of indirection however. Some general feedback:
RIVRecord(std::string _name, std::vector<T> _values)
Is better as:
RIVRecord(const std::string& _name, const std::vector<T>& _values)
In order to avoid unnecessary copies, overall the rule of thumb is to accept arguments as const& for most things which aren't a primitive.
T* Value(int index) { return &values[index]; }
Is dangerous, if the size() goes beyond capacity() of your vector< T > it will reallocate and invalidate all your pointers. A better interface in my opinion would be to have a T GetValue< T >() & void SetValue< T >( T a_Value ).
On to type erasure, this is how RIVDataSet could look, I'm using a library called Loki here, if you don't want to use Loki I'll give you some pointers afterwards.
class RIVDataSet
{
private :
//How to template this??
struct HolderBase
{
virtual ~HolderBase() {}
};
template< typename T >
struct HolderImpl : HolderBase
{
// Use pointer to guarantee validity of returned record
std::vector< RIVRecord< T >* > m_Record;
};
typedef Loki::AssocVector< Loki::TypeInfo, HolderBase* > HolderMap;
HolderMap m_Records;
public:
~RIVDataSet()
{
for( HolderMap::iterator itrCur = m_Records.begin(); itrCur != m_Records.end(); ++itrCur ) delete itrCur->second;
}
//And this
template< typename T >
void AddRecord(const RIVRecord< T >& record )
{
HolderMap::iterator itrFnd = m_Records.find( typeid( T ) );
if( itrFnd == m_Records.end() )
itrFnd = m_Records.insert( std::make_pair( Loki::TypeInfo( typeid( T ) ), new HolderImpl< T >() ) ).first;
static_cast< HolderImpl< T >* >( itrFnd->second )->m_Record.push_back( new RIVRecord< T >( record ) );
}
template< typename T >
RIVRecord< T >* GetRecord()
{
HolderMap::iterator itrFnd = m_Records.find( typeid( T ) );
assert( itrFnd != m_Records.end() );
return itrFnd == m_Records.end() ? 0 : static_cast< HolderImpl< T >* >( itrFnd->second )->m_Record.front();
}
};
Loki::AssocVector can be substituted for std::map, you do however need Loki::TypeInfo, which is just a wrapper for std::type_info. It's fairly easy to implement one your self if you take a look at the code for it in Loki.
One horrible idea if you really must do it as general is using the "type erasure idiom". It goes something like this (haven't compiled that though but I think it will, and can be further improved by type traits that would link RIVRecordsIndex::Float to the type float and prevent error)
class BaseRIVRecord
{
};
template <class T>
class RIVRecord : public BaseRIVRecord
{
};
enum class RIVRecordsIndex
{
Float, Int
};
class RIVDataSet
{
public:
template<RIVRecordsIndex I, typename T>
void addRecord()
{
allmightyRecords.resize(I+1);
allmightyRecords[I].push_back(new RIVRecord<T>());
}
template<RIVRecordsIndex I, typename T>
RIVRecord<T>* get(unsigned int index)
{
return static_cast<RIVRecord<T>*>(allmighyRecords[I][index]);
}
private:
std::vector<std::vector<BaseRIVRecord*>> allmightyRecords;
};
int main()
{
RIVDataSet set;
set.addRecord<RIVRecordsIndex::Float, float>();
set.addRecord<RIVRecordsIndex::Float, float>();
set.addRecord<RIVRecordsIndex::Int, int>();
RIVRecord<int> r = set.get<RIVRecordsIndex::Int, int>(0);
}
If you decide to do this stuff make sure you do not slice the inherited type (i.e. use vector of pointers). Do use some kind of type traits to prevent error calls like set.get. Again I have no time to actually compile that, it is just an idea thrown to further develop.
You can't use variadic templates to create multiple members of the same name but different type. In fact, you can never have two members with the same name. However, you can use multiple inheritance, and put the member in your base classes using variadic base classes. You can then use a member template in your derived class to resolve the ambiguity.
The example below also uses perfect forwarding to make sure that if a temporary is passed to add(), its resources can be "stolen". You can read more about that here.
Here is the example:
#include <vector>
#include <utility>
// This templated base class holds the records for each type.
template <typename T>
class Base {
public:
// "T &&v" is a universal reference for perfect forwarding.
void add(T &&v) { records.push_back(std::forward<T>(v)); }
private:
std::vector<T> records;
};
// This inherits from Base<int>, Base<double>, for example, if you instantiate
// DataSet<int, double>.
template <typename... Ts>
class DataSet : public Base<Ts>... {
public:
// The purpose of this member template is to resolve ambiguity by specifying
// which base class's add() function we want to call. "U &&u" is a
// universal reference for perfect forwarding.
template <typename U>
void add(U &&u) {
Base<U>::add(std::forward<U>(u));
}
};
int main() {
DataSet<int, double> ds;
ds.add(1);
ds.add(3.14);
}

A generic Functor class in C++

I was trying to built atop the thread here: Variable length template arguments list?
to have a default Functor class, this is only of academic interest. My goal is to build a generic Fucntor class: given a class name, method name and argument types(of variable length), it builds a class that has an operator() method which takes variable number of arguments of type specified in template args and takes a pointer and applies the given method. Imagine a class thus:
class MyClass
{
public:
float Fraction( float n, int m)
{
return n/m;
}
int Increment(int n)
{
return n+1;
}
} ;
And a templatized functor class that can be used in any function thus:
int k = FunctorClass<MyClass, Increment, int, int /*return type*/> (3);
assert(k == 4);
float l = FunctorClass<MyClass, Fraction, float, int, float, /*return type*/> (4,3);
assert(l == (4/3));
Can such a functor class be constructed?
Sidenote: Cant use Variadic templates, (building in VS2010, no ... template arguments)
Thanks for the help
This is certainly doable, e.g. Boost bind() uses this approach under the hood. Without variadics you won't get full generality, however, because you will be limited to a fixed number of template arguments and you need to type the implementation for each different number of arguments you want to support. Also, without rvalue references you won't get perfect forwarding.
That said, the way you are trying to use it won't work: when stating the member functions, you can't just name them. You need to obtain the correct member function point using e.g. &MyClass::Increment and &MyClass::Fraction. If the member function is overloaded, you need to disambiguate it.
Since you apparently want to enable the use of this function object for non-static member functions, you also need to provide an object on which the member function is to be called. The most reasonable approach for this is to pass a reference to the object as a constructor argument of the function object class and to store it to be used whenever the function is being called. That is, the use looks somewhat different but it can be simplified with some sort of factory function. Here is a version which adjusts the various things and implements a corresponding function object template:
#include <cassert>
// -----------------------------------------------------------------------------
template <typename T, T> class FunctorClass;
template <typename RC, typename Class,
RC (Class::*Member)()>
class FunctorClass<RC (Class::*)(), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()() const { return (this->object_->*Member)(); }
private:
Class* object_;
};
template <typename RC, typename Class, typename A0,
RC (Class::*Member)(A0)>
class FunctorClass<RC (Class::*)(A0), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()(A0 a0) const { return (this->object_->*Member)(a0); }
private:
Class* object_;
};
template <typename RC, typename Class, typename A0, typename A1,
RC (Class::*Member)(A0, A1)>
class FunctorClass<RC (Class::*)(A0, A1), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()(A0 a0, A1 a1) const { return (this->object_->*Member)(a0, a1); }
private:
Class* object_;
};
// -----------------------------------------------------------------------------
class MyClass
{
public:
int foo() { return 17; }
float Fraction( float n, int m)
{
return n/m;
}
int Increment(int n)
{
return n+1;
}
};
int main()
{
MyClass object;
int i = FunctorClass<int (MyClass::*)(), &MyClass::foo>(object)();
assert(i == 17);
int k = FunctorClass<int (MyClass::*)(int), &MyClass::Increment>(object)(3);
assert(k == 4);
float l = FunctorClass<float (MyClass::*)(float, int), &MyClass::Fraction>(object)(4,3);
assert(l == (4.0f/3));
}
I'm not sure you would need variadics to pull this off. Consider the following interface...
template < typename RETURN_TYPE >
class iFunctor abstract {
public:
virtual RETURN_TYPE operator () ( void ) = 0;
};
Abstract interfaces are not full-blown classes, they can contain a partial implementation such as function signatures and some data members. With the template, you can generalized a return type. But what about the argument list you say?
Note how there is no constructor in the interface. In your concrete class (or derived classes) you can pass the burden of variable argument lists to the constructor, like so...
template < typename TYPE >
class ConcreteFunctor_add : public iFunctor < TYPE > {
private:
int A;
int B;
public:
explicit ConcreteFunctor_add ( const int &a, const int &b ) : A(a), B(b) {};
TYPE operator () ( void ) { return ( A + B ); };
};
You deal with the argument list on a case by case basis through the constructor.
The explicit constructor requires an argument list upon declaration, so you'll get your variable list here. So in practice...
ConcreteFunctor_add < int > addInteger ( 10, 10 );
addInteger();
...and you'd be cool.