Related
I have a Curiously Recurring Template Pattern (CRTP) interface-class where I want to memoize evaluations for all methods defined by the derived classes. I also have return values whose types are template-defined. Example:
template <class Derived, class Ret1, class Ret2>
class memoization_class
{
int operator_iter, Eval_1_iter, Eval_2_iter;
double data_operator;
Ret1 data_Eval_1;
Ret2 data_Eval_2;
public:
//Desired memoization:
double operator()(const double &arg, const int& iter)
{
if (iter != operator_iter)
{
data_operator = static_cast<Derived *>(this)->operator(arg);
operator_iter = iter;
return data_operator;
}
else
{
return data_operator;
}
}
//Want to create the same buffer for an arbitrary return type, for an arbitrary amount of methods
Ret1 Eval_1(const double &arg, const int& iter)
{
return static_cast<Derived *>(this)->Eval_1(arg);
}
Ret2 Eval_2(const double &arg, const int& iter)
{
return static_cast<Derived *>(this)->Eval_2(arg);
}
};
Is it possible to generalize this behaviour to something like this:
template <class Derived, class Ret1, class Ret2>
class memoization_class
{
int operator_iter, Eval_1_iter, Eval_2_iter;
double data_operator;
Ret1 data_Eval_1;
Ret2 data_Eval_2;
public:
double operator()(const double &arg, const int& iter)
{
return memoize(&static_cast<Derived *>(this)->operator(), arg, iter);
}
//..
};
Edit: Here is the application for the problem. It uses Eigen, and may return Sparse or Dense matrices/vectors. (The class provides functions for optimizing nonlinear problems)
MatrixBase is in this case a substitute for Vec in order to allow Eigen to pass all kinds of unevaluated expressions.
#ifndef OBJECTIVE_HPP
#define OBJECTIVE_HPP
#include "EigenDataTypes.hpp"
// template <class Base, class Mat>
// using is_Base = std::enable_if_t<std::is_base_of<Base, Mat>::value>;
// template <class Derived, class Vec, class Mat, typename Enable = void>
// struct objective;
template <class Derived, class Vec, class Mat>
struct objective
{
protected:
int Nx_, nnzh_;
public:
objective(const int &Nx, const int &nnzh) : Nx_(Nx), nnzh_(nnzh) {}
template <typename T>
inline scalar operator()(const MatrixBase<T> &x)
{
return static_cast<Derived *>(this)->operator()(x);
}
template <typename T>
inline Vec Eval_grad(const MatrixBase<T> &x)
{
return static_cast<Derived *>(this)->Eval_grad(x);
}
template <typename T>
inline Mat Eval_hessian(const MatrixBase<T> &x)
{
return static_cast<Derived *>(this)->Eval_hessian(x);
}
template <typename T>
inline scalar operator()(const SparseMatrixBase<T> &x)
{
return static_cast<Derived *>(this)->operator()(x);
}
template <typename T>
inline Vec Eval_grad(const SparseMatrixBase<T> &x)
{
return static_cast<Derived *>(this)->Eval_grad(x);
}
template <typename T>
inline Mat Eval_hessian(const SparseMatrixBase<T> &x)
{
return static_cast<Derived *>(this)->Eval_hessian(x);
}
inline int Get_Nx()
{
return Nx_;
}
inline int Get_nnzh()
{
return nnzh_;
}
};
EigenDataTypes.hpp:
#ifndef EIGENDATATYPES_H
#define EIGENDATATYPES_H
#include <Eigen/Dense>
#include <Eigen/Sparse>
using scalar = Eigen::Matrix<double, 1, 1>;
using Eigen::MatrixXd;
using Eigen::VectorXd;
using spVec = Eigen::SparseVector<double>;
using spMat = Eigen::SparseMatrix<double>;
using dVec = Eigen::VectorXd;
using dMat = Eigen::MatrixXd;
using Eigen::MatrixBase;
using Eigen::SparseMatrixBase;
using Triplet = Eigen::Triplet<double>;
#endif
Edit 2: Here is my rather verbose implementation of memoization for the objective-class. (It checks for change in input x instead of iteration-change):
template <class Data>
struct memData
{
dVec x;
Data data;
memData(const int &Nx) : x(Nx)
{
}
};
inline bool
is_memoized(const dVec &x, const dVec &x_mem)
{
return ((x - x_mem).array().abs() <= std::numeric_limits<double>::epsilon()).all();
}
template <class Derived, class Vec, class Mat>
struct objective_memoized : public objective<objective_memoized<Derived, Vec, Mat>, Vec, Mat>
{
protected:
int &Nx_ = objective<objective_memoized<Derived, Vec, Mat>, Vec, Mat>::Nx_;
int &nnzh_ = objective<objective_memoized<Derived, Vec, Mat>, Vec, Mat>::nnzh_;
memData<scalar> mem_operator;
memData<Vec> mem_Eval_grad;
memData<Mat> mem_Eval_hessian;
public:
objective_memoized(const int &Nx, const int &nnzh) : objective<objective_memoized<Derived, Vec, Mat>, Vec, Mat>(Nx, nnzh),
mem_operator(Nx),
mem_Eval_grad(Nx),
mem_Eval_hessian(Nx)
{
}
objective_memoized(const int &Nx, const int &Ns, const int &nnzh) : objective<objective_memoized<Derived, Vec, Mat>, Vec, Mat>(Nx, nnzh),
mem_operator(Nx + Ns),
mem_Eval_grad(Nx + Ns),
mem_Eval_hessian(Nx + Ns)
{
}
template <typename T>
inline scalar operator()(const MatrixBase<T> &x)
{
if (!is_memoized(x, mem_operator.x))
{
mem_operator.data = static_cast<Derived *>(this)->operator()(x);
mem_operator.x = x;
}
return mem_operator.data;
}
template <typename T>
inline Vec Eval_grad(const MatrixBase<T> &x)
{
if (!is_memoized(x, mem_Eval_grad.x))
{
mem_Eval_grad.data = static_cast<Derived *>(this)->Eval_grad(x);
mem_Eval_grad.x = x;
}
return mem_Eval_grad.data;
}
template <typename T>
inline Mat Eval_hessian(const MatrixBase<T> &x)
{
if (!is_memoized(x, mem_Eval_hessian.x))
{
mem_Eval_hessian.data = static_cast<Derived *>(this)->Eval_hessian(x);
mem_Eval_hessian.x = x;
}
return mem_Eval_hessian.data;
}
template <typename T>
inline scalar operator()(const SparseMatrixBase<T> &x)
{
if (!is_memoized(x, mem_operator.x))
{
mem_operator.data = static_cast<Derived *>(this)->operator()(x);
mem_operator.x = x;
}
return mem_operator.data;
}
template <typename T>
inline Vec Eval_grad(const SparseMatrixBase<T> &x)
{
if (!is_memoized(x, mem_Eval_grad.x))
{
mem_Eval_grad.data = static_cast<Derived *>(this)->Eval_grad(x);
mem_Eval_grad.x = x;
}
return mem_Eval_grad.data;
}
template <typename T>
inline Mat Eval_hessian(const SparseMatrixBase<T> &x)
{
if (!is_memoized(x, mem_Eval_hessian.x))
{
mem_Eval_hessian.data = static_cast<Derived *>(this)->Eval_hessian(x);
mem_Eval_hessian.x = x;
}
return mem_Eval_hessian.data;
}
};
TLDR; I want to return stored data if it has been evaluated previously this iteration, or evaluate, store & return if not. Can I use one function to define this for all return types?
I want to implement a static cast to one of the classes from a set, passed as variadic template parameters:
struct Base {
int tag_value;
};
struct Derived1 : public Base {
static constexpr int tag = 1;
Derived1() : Base{tag} {}
int foo() { return 100; }
};
struct Derived2 : public Base {
static constexpr int tag = 2;
Derived2() : Base{tag} {}
int foo() { return 200; }
};
struct Derived3 : public Base {
static constexpr int tag = 3;
Derived3() : Base{tag} {}
int foo() { return 300; }
};
template <class ... Candidates, class Fn>
auto apply_casted(Base & base, Fn fn) {
//compare base::tag_value with each Candidate::tag
//static_cast<> base to Candidate if match
//call fn with base casted to matched Derived
return fn(/*...*/);
}
int main() {
Derived2 d2;
Base & b = d2;
// should throw error (b.tag_value doesn't match neither Derived1::tag nor Derived3::tag
auto v1 = apply_casted<Derived1, Derived3>(b, [](auto d) {
return d.foo();
});
// should static_cast b to Derived2 and return foo() (200)
auto v2 = apply_casted<Derived1, Derived2>(b, [](auto d) {
return d.foo(); //calls Derived2::foo()
});
}
Well, I hope the code speaks for itself. Code to get started: https://godbolt.org/z/WfaFt-
I'm looking for implementation of apply_casted. How to iterate Candidates... at compile time is probably the most difficult part.
template <typename Candidate, typename... Candidates, typename Fn>
auto apply_casted(Base& base, Fn&& fn)
{
if (base.tag_value == Candidate::tag)
{
return std::forward<Fn>(fn)(static_cast<Candidate&>(base));
}
if constexpr (sizeof...(Candidates) > 0)
{
return apply_casted<Candidates...>(base, std::forward<Fn>(fn));
}
else
{
throw std::runtime_error{"tag_value doesn't match"};
}
}
DEMO
If the return types can differ, a common one should be specified as a result of apply_casted:
std::common_type_t<std::invoke_result_t<Fn, Candidate&>
, std::invoke_result_t<Fn, Candidates&>...>
A similar functionality can be achieved with std::variant:
template <typename... Ts> struct overload : Ts... { using Ts::operator()...; };
template <typename... Ts> overload(Ts...) -> overload<Ts...>;
std::variant<Derived1, Derived2, Derived3> v;
v.emplace<Derived2>();
std::visit(overload{ [](Derived2& d) -> int { return d.foo(); },
[](auto& d) -> int { throw std::runtime_error{""}; } }, v);
DEMO 2
For a better performance, you should use a jump table, similar to the below one:
template <typename R, typename F, typename V, typename C>
struct invoker
{
static R invoke(F&& f, V&& v)
{
return f(static_cast<C&&>(v));
}
};
template <typename Candidate, typename... Candidates, typename Fn>
auto apply_casted(Base& base, Fn&& fn)
{
using R = std::common_type_t<std::invoke_result_t<Fn, Candidate&>
, std::invoke_result_t<Fn, Candidates&>...>;
using invoker_t = R(*)(Fn&&, Base&);
invoker_t arr[]{ &invoker<R, Fn, Base&, Candidate&>::invoke
, &invoker<R, Fn, Base&, Candidates&>::invoke... };
return arr[base.tag_value](std::forward<Fn>(fn), base);
}
DEMO 3
It's too late too play?
You tagged C++17, so you can use template folding (modified following a Frank's suggestion (thanks!))
template <class ... Candidates, class Fn>
auto apply_casted(Base & base, Fn fn)
{
int ret {-1};
if ( false == ((Candidates::tag == base.tag_value
? ret = fn(static_cast<Candidates&>(base)), true
: false) || ...) )
; // throw something
return ret;
}
I have a template function:
template<typename R, typename... T>
void function(const std::string& id, R (*f)(T...)) {
switch (sizeof...(T)) {
case 0: f0compile<R>(reinterpret_cast<void (*)()>(f)); break;
case 1: f1compile<R, T>(reinterpret_cast<void (*)()>(f)); break;
case 2: f2compile<R, T1, T2>(reinterpret_cast<void (*)()>(f)); break;
}
...
}
How can I call these functions (f0compile, f1compile, f2compile) ? How can I write the "function" ?
template<typename R>
void f0compile(void (*f)()) {
new F0<R>(f):
...
}
template<typename R, typename T>
void f1compile(void (*f)()) {
new F1<R,T>(f);
...
}
template<typename R, typename T1, typename T2>
void f2compile(void (*f)()) {
new F2<R,T1,T2>(f);
...
}
Thank you for help with these variadic template.
I add the implementation of F0 F1 F2:
template <typename R> struct F0 : F {
F0(void (*_fn)()) : F(typeid(R))
, fn(reinterpret_cast<R(*)()>(_fn))
{}
const void* f() { res = fn(); return &res; }
R res; R (*fn)();
void d() { delete this; }
};
template <typename R, typename T> struct F1 : F {
F1(void (*_fn)(), F* _opd) : F(typeid(R))
, fn(reinterpret_cast<R(*)(T)>(_fn))
, opd(autocast<T>(_opd))
{}
const void* f() { res = fn(*(T*) opd->f()); return &res; }
F* opd;
R res; R (*fn)(T);
void d() { opd->d(); delete this; }
};
template <typename R, typename T1, typename T2> struct F2 : F {
F2(void (*_fn)(), F* _opd1, F* _opd2) : F(typeid(R))
, fn(reinterpret_cast<R(*)(T1,T2)>(_fn))
, opd1(autocast<T1>(_opd1))
, opd2(autocast<T2>(_opd2))
{}
const void* f() { res = fn(*(T1*) opd1->f(), *(T2*) opd2->f()); return &res; }
F* opd1; F* opd2;
R res; R (*fn)(T1,T2);
void d() { opd1->d(); opd2->d(); delete this; }
};
Thank you
struct F {
F(const std::type_info& _type) : type(_type) {}
virtual ~F() {}
const std::type_info& type;
virtual const void* f() = 0;
virtual void d() = 0;
};
Added class F . It rapresent each function / operand on the stack
template <typename T> struct Opd : F {
Opd(T _opd) : F(typeid(T)), res(_opd) { }
const void* f() { return &res; }
T res;
void d() { delete this; }
};
Added class Opd . It represent a specific operand on the stack.
The real program is this (simplified):
double foo(double op1, double op2) {
return op1 + op2;
}
#include <functional>
#include <stack>
#include <type_traits>
class Expression {
public:
struct F {
F(const std::type_info& _type) : type(_type) {}
virtual ~F() {}
const std::type_info& type;
virtual const void* f() = 0;
virtual void d() = 0;
};
public:
Expression() : m_cexpr(NULL) {}
~Expression() {
if (m_cexpr) m_cexpr->d();
}
// function
template<typename R, typename... T> void function(R (*f)(T...), void (*compile)(void (*)(), std::stack<F*>&)) {
m_f = std::make_pair(reinterpret_cast<void (*)()>(f), compile);
}
template<typename R, typename T1, typename T2> static void f2compile(void (*f)(), std::stack<F*>& s) {
auto opd2 = s.top();
s.pop();
auto opd1 = s.top();
s.pop();
s.push(new F2<R,T1,T2>(f, opd1, opd2));
}
void compile() {
if (m_cexpr) m_cexpr->d();
std::stack<F*> s;
s.push(new Opd<double>(1));
s.push(new Opd<double>(2));
m_f.second(m_f.first, s);
m_cexpr = s.top();
s.pop();
assert(s.empty());
}
void* execute() {
return const_cast<void*>(m_cexpr->f());
}
const std::type_info& type() {
return m_cexpr->type;
}
private:
F* m_cexpr;
std::pair<void (*)(), void (*)(void (*)(), std::stack<F*>&)> m_f;
template <typename T> struct Opd : F {
Opd(T _opd) : F(typeid(T)), res(_opd) {}
const void* f() { return &res; }
T res;
void d() { delete this; }
};
template <typename R, typename T1, typename T2> struct F2 : F {
F2(void (*_fn)(), F* _opd1, F* _opd2) : F(typeid(R))
, fn(reinterpret_cast<R(*)(T1,T2)>(_fn))
, opd1(_opd1)
, opd2(_opd2)
{}
const void* f() { res = fn(*(T1*) opd1->f(), *(T2*) opd2->f()); return &res; }
F* opd1; F* opd2;
R res; R (*fn)(T1,T2);
void d() { opd1->d(); opd2->d(); delete this; }
};
};
TEST_CASE("expression") {
Expression e;
e.function(foo, e.f2compile<double, double, double>);
e.compile();
e.execute();
REQUIRE(e.type() == typeid(double));
REQUIRE(*static_cast<double*>(e.execute()) == 3);
}
And my problem is how write better code c++11 using variadic template. How write a function "fNcompile" and a function "FN" with variadic template.
I don't think you need the variadic template. Instead:
template<typename R>
void fcompile(void (*f)()) {
new F0<R>(reinterpret_cast<void (*)()>(f));
...
}
template<typename R, typename T>
void fcompile(void (*f)(T)) {
new F1<R,T>(reinterpret_cast<void (*)()>(f));
...
}
template<typename R, typename T1, typename T2>
void fcompile(void (*f)(T1, T2)) {
new F1<R,T1,T2>(reinterpret_cast<void (*)()>(f));
...
}
Now you can call fcompile<some_type>(some_func) for any some_type and any nullary/unary/binary some_func which returns void.
To answer the specific question, below are variadic FN and fNcompile as close as possible to your existing code. First, though, since you said you're working in C++11, we'll need an equivalent of std::make_index_sequence from C++14. Here's a simple one. You can search for others that are smarter about being less likely to hit compiler template limitations...
namespace cxx_compat {
template <typename T, T... Values>
struct integer_sequence {
static constexpr std::size_t size() const
{ return sizeof...(Values); }
};
template <typename T, T Smallest, T... Values>
struct make_integer_sequence_helper {
static_assert(Smallest > 0,
"make_integer_sequence argument must not be negative");
using type = typename make_integer_sequence_helper<
T, Smallest-1, Smallest-1, Values...>::type;
};
template <typename T, T... Values>
struct make_integer_sequence_helper<T, 0, Values...> {
using type = integer_sequence<T, Values...>;
};
template <typename T, T N>
using make_integer_sequence =
typename make_integer_sequence_helper<T, N>::type;
template <std::size_t... Values>
using index_sequence = integer_sequence<std::size_t, Values...>;
template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
template <typename... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
} // end namespace cxx_compat
And now, the actual FN and fNcompile:
template <typename R, typename ...T> struct FN : F {
private:
template <typename T>
using any_to_Fstar = F*;
public:
FN(void (*_fn)(), any_to_Fstar<T> ... _opd) : F(typeid(R))
, fn(reinterpret_cast<R(*)(T...)>(_fn))
, opd{_opd...}
{}
FN(R (*_fn)(T...)) : F(typeid(R)), fn(_fn), opd() {}
const void* f() {
f_helper(cxx_compat::index_sequence_for<T...>{});
return &res;
}
std::array<F*, sizeof...(T)> opd;
R res; R (*fn)(T...);
void d() {
for (F* o : opd)
o->d();
delete this;
}
private:
template <std::size_t... Inds>
void f_helper(cxx_compat::index_sequence<Inds...>)
{ res = fn(*(T*) opd[Inds]->f() ...); }
};
template<typename R, typename... T>
static void fNcompile(void (*f)(), std::stack<F*>& s) {
auto* f_obj = new FN<R, T...>(f);
for (std::size_t ind = sizeof...(T); ind > 0;) {
f_obj->opd[--ind] = s.top();
s.pop();
}
s.push(f_obj);
}
What's going on:
To actually call the function pointer, we need access to a number of function arguments at the same time, so to replace the named members opd1, opd2 with a number of F* pointers determined by template instantiation, we use a std::array<F*, sizeof...(T)>, since sizeof...(T) is the number of argument types provided to the template.
For compatibility with the F2 constructor you declared, any_to_Fstar<T> ... _opd declares a number of constructor parameters to match the number of T template arguments, all with the same type F*. (But now fNcompile uses the additional constructor taking just the function pointer instead, and sets the array members afterward.)
To get at these pointers and pass them all to fn in one expression, we need to expand some sort of variadic pack. Here's where index_sequence comes in:
index_sequence_for<T...> is a type alias for index_sequence with a sequence of numbers counting up from zero as template arguments. For example, if sizeof...(T) is 4, then index_sequence_for<T...> is index_sequence<0, 1, 2, 3>.
f just calls a private function f_helper, passing it an object of that index_sequence_for<T...> type.
The compiler can deduce the template argument list for f_helper from matching the index_sequence types: Inds... must be that same sequence of numbers counting up from zero.
In the f_helper body, the expression fn(*(T*) opd[Inds]->f() ...) is instantiated by expanding both the template parameter packs T and Inds to get one list of function arguments for calling fn.
However, use of void pointers and reinterpret_cast is dangerous and rarely actually necessary in C++. There's almost always a safer way using templates. So I'd redesign this to be something more like:
#include <type_traits>
#include <typeinfo>
#include <stdexcept>
#include <memory>
#include <stack>
namespace cxx_compat {
// Define integer_sequence and related templates as above.
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&& ... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
} // end namespace cxx_compat
class bad_expression_type : public std::logic_error
{
public:
bad_expression_type(const std::type_info& required,
const std::type_info& passed)
: logic_error("bad_argument_type"),
required_type(required),
passed_type(passed) {}
const std::type_info& required_type;
const std::type_info& passed_type;
};
class Expression
{
public:
class F
{
public:
F() noexcept = default;
F(const F&) = delete;
F& operator=(const F&) = delete;
virtual ~F() = default;
virtual const std::type_info& type() const noexcept = 0;
virtual void compile(std::stack<std::unique_ptr<F>>&) = 0;
template <typename R>
R call_R() const;
};
using F_ptr = std::unique_ptr<F>;
using F_stack = std::stack<F_ptr>;
template <typename R>
class Typed_F : public F
{
public:
const std::type_info& type() const noexcept override
{ return typeid(R); }
virtual R call() const = 0;
};
// Accepts any callable: function pointer, lambda, std::function,
// other class with operator().
template <typename R, typename... T, typename Func,
typename = typename std::enable_if<std::is_convertible<
decltype(std::declval<const Func&>()(std::declval<T>()...)),
R>::value>::type>
void function(Func func)
{
store_func<R, T...>(std::move(func));
}
// Overload for function pointer that does not need explicit
// template arguments:
template <typename R, typename... T>
void function(R (*fptr)(T...))
{
store_func<R, T...>(fptr);
}
template <typename T>
void constant(const T& value)
{
store_func<T>([value](){ return value; });
}
void compile(F_stack& stack)
{
m_cexpr->compile(stack);
}
private:
template <typename Func, typename R, typename... T>
class F_Impl : public Typed_F<R>
{
public:
F_Impl(Func func) : m_func(std::move(func)) {}
void compile(F_stack& stack) override {
take_args_helper(stack, cxx_compat::index_sequence_for<T...>{});
}
R call() const override {
return call_helper(cxx_compat::index_sequence_for<T...>{});
}
private:
template <typename Arg>
int take_one_arg(std::unique_ptr<Typed_F<Arg>>& arg, F_stack& stack)
{
auto* fptr = dynamic_cast<Typed_F<Arg>*>(stack.top().get());
if (!fptr)
throw bad_expression_type(
typeid(Arg), stack.top()->type());
arg.reset(fptr);
stack.top().release();
stack.pop();
return 0;
}
template <std::size_t... Inds>
void take_args_helper(F_stack& stack, cxx_compat::index_sequence<Inds...>)
{
using int_array = int[];
(void) int_array{ take_one_arg(std::get<Inds>(m_args), stack) ..., 0 };
}
template <std::size_t... Inds>
R call_helper(cxx_compat::index_sequence<Inds...>) const {
return m_func(std::get<Inds>(m_args)->call()...);
}
Func m_func;
std::tuple<std::unique_ptr<Typed_F<T>>...> m_args;
};
template <typename R, typename... T, typename Func>
void store_func(Func func)
{
m_cexpr = cxx_compat::make_unique<F_Impl<Func, R, T...>>(
std::move(func));
}
F_ptr m_cexpr;
};
template <typename R>
R Expression::F::call_R() const
{
auto* typed_this = dynamic_cast<const Typed_F<R>*>(this);
if (!typed_this)
throw bad_expression_type(typeid(R), type());
return typed_this->call();
}
TEST_CASE("expression") {
Expression a;
a.constant(1.0);
Expression b;
b.constant(2.0);
Expression c;
c.function(+[](double x, double y) { return x+y; });
Expression::F_stack stack;
a.compile(stack);
REQUIRE(stack.size() == 1);
b.compile(stack);
REQUIRE(stack.size() == 2);
c.compile(stack);
REQUIRE(stack.size() == 1);
REQUIRE(stack.top() != nullptr);
REQUIRE(stack.top()->type() == typeid(double));
REQUIRE(stack.top()->call_R<double>() == 3.0);
}
It would also be possible, but a bit tricky, to support reference and const variations of the argument and result types, for example, using a std::string(*)() function as an argument to an unsigned int(*)(const std::string&) function.
I have a templated class with variable numbers of templated arguments. As in these cases (I cannot afford C++11) a good practice is to create a default class that we call none and put it as default like below.
struct none {};
template<class T1=none, T2=none, T3=none>
class A{
template<class T>
double extract() { return none();}
template<>
double extract<T1>() { return m1_();}
template<>
double extract<T2>() { return m2_();}
template<>
double extract<T3> () { return m3_();}
T1 m1_;
T2 m2_;
T3 m3_;
};
At this stage I don't know how to implement a generic/templated accessor function that can access each of the templated argument.
All of the templated arguments are different so I specialized A::extract() for each of the templated arguments.
Is there any better way to do this? Any sort of tagging I can have a look at?
struct none {};
template <class T, class N>
class Holder : public N
{
protected:
T m;
typedef Holder<T, N> First;
double extractP(T*) { return m(); }
template <class X> double extractP(X*) {
return this->N::extractP(static_cast<X*>(0));
}
};
template <class T>
class Holder<T, none>
{
protected:
T m;
typedef Holder<T, none> First;
double extractP(T*) { return m(); }
template <class X> none extractP(X*) {
return none();
}
};
template <class T1 = none, class T2 = none, class T3 = none>
class A : Holder<T1, Holder<T2, Holder<T3, none> > >
{
public:
template <class T> double extract() {
return this->extractP(static_cast<T*>(0));
}
};
A similarly-named solution to n.m but more on the Boost's Variant class design.
The suggestion is to use a Variant container (a generic container for your objects) and use accessors directly on them.
#include <iostream>
#include <stdexcept>
using namespace std;
class BaseHolder
{
public:
virtual ~BaseHolder(){}
virtual BaseHolder* clone() const = 0;
};
template<typename T>
class HoldData : public BaseHolder
{
public:
HoldData(const T& t_) : t(t_){}
virtual BaseHolder* clone() const {
return new HoldData<T>(t);
}
T getData() {
return t;
}
private:
T t;
};
class Variant
{
public:
Variant() : data(0) {}
template<typename T>
Variant(const T& t) : data(new HoldData<T>(t)){}
Variant(const Variant& other) : data(other.data ? other.data->clone() : 0) {}
~Variant(){delete data;}
template<typename T>
T getData() {
return ((HoldData<T>*)data)->getData();
}
private:
BaseHolder* data;
private:
Variant& operator=(const Variant& other) { return *this;} // Not allowed
};
struct none {};
class Container{
public:
Container() : m1_(0), m2_(0), m3_(0){}
~Container() {
if(m1_)
delete m1_;
if(m2_)
delete m1_;
if(m3_)
delete m1_;
}
none extract() { return none();}
template<typename T>
void insertM1(T obj) {
m1_ = new Variant(obj);
}
template<typename T>
T extractM1() {
if(m1_ != 0)
return m1_->getData<T>();
else
throw std::runtime_error("Element not set");
}
// TODO: implement m2 and m3
Variant *m1_;
Variant *m2_;
Variant *m3_;
};
int main() {
Container obj;
char M1 = 'Z';
obj.insertM1(M1);
char extractedM1 = obj.extractM1<char>();
cout << extractedM1;
return 0;
}
http://ideone.com/BaCWSV
Your class seems to mimic std::tuple, which, unfortunately for you, was added in C++11. The good news is that you can use boost::tuple instead.
As an example of usage:
boost::tuple<std::string, double> t = boost::make_tuple("John Doe", 4.815162342);
std::cout << boost::get<0>(t) << '\n';
std::cout << boost::get<1>(t) << '\n';
Live demo
Without access to C++11, it's a bit uglier, but you can leverage Boost.Tuple:
#include <iostream>
#include <boost/tuple/tuple.hpp>
template <size_t I, typename T, typename U>
struct AccessImpl;
template <size_t I, typename T, typename U>
struct AccessImpl {
template <typename Tuple>
static T& impl(Tuple& tuple) {
typedef typename ::boost::tuples::element<I+1, Tuple>::type Next;
return AccessImpl<I+1, T, Next>::impl(tuple);
}
};
template <size_t I, typename T>
struct AccessImpl<I, T, T> {
template <typename Tuple>
static T& impl(Tuple& tuple) { return boost::get<I>(tuple); }
};
template <typename T, typename Tuple>
T& access(Tuple& tuple) {
typedef typename ::boost::tuples::element<0, Tuple>::type Head;
return AccessImpl<0, T, Head>::impl(tuple);
}
int main() {
boost::tuples::tuple<char, int, std::string> example('a', 1, "Hello, World!");
std::cout << access<std::string>(example) << "\n";
return 0;
}
This, as expected, prints "Hello, World!".
Suppose we want to apply a series of transformations, int f1(int), int f2(int), int f3(int), to a list of objects. A naive way would be
SourceContainer source;
TempContainer1 temp1;
transform(source.begin(), source.end(), back_inserter(temp1), f1);
TempContainer2 temp2;
transform(temp1.begin(), temp1.end(), back_inserter(temp2), f2);
TargetContainer target;
transform(temp2.begin(), temp2.end(), back_inserter(target), f3);
This first solution is not optimal because of the extra space requirement with temp1 and temp2. So, let's get smarter with this:
int f123(int n) { return f3(f2(f1(n))); }
...
SourceContainer source;
TargetContainer target;
transform(source.begin(), source.end(), back_inserter(target), f123);
This second solution is much better because not only the code is simpler but more importantly there is less space requirement without the intermediate calculations.
However, the composition f123 must be determined at compile time and thus is fixed at run time.
How would I try to do this efficiently if the composition is to be determined at run time? For example, if this code was in a RPC service and the actual composition--which can be any permutation of any subset of f1, f2, and f3--is based on arguments from the RPC call.
EDIT: Working version at http://ideone.com/5GxnW . The version below has the ideas but does not compile. It supports run time type checking, and run time function composition.
The idea is to define a generic (unary) function class, and a way to compose them with run time type checks. This is done with a combination of boost::any, boost::function and the type erasure idiom.
#include <boost/any.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
template <typename T>
struct identity
{
T operator()(const T& x) { return x; }
};
struct any_function
{
template <typename Res, typename Arg>
any_function(boost::function<Res, Arg> f)
{
impl = make_impl(f);
}
boost::any operator()(const boost::any& x)
{
return impl->invoke(x);
}
static any_function compose(const any_function& f,
const any_function& g)
{
any_function ans;
ans.impl = compose_impl(f.impl, g.impl);
return ans;
}
template <typename T>
static any_function id()
{
using boost::function
return any_function(function<T(T)>(identity<T>()));
}
template <typename Res, typename Arg>
boost::function<Res(Arg)> to_function()
{
using boost::function;
return function<Res(Arg)>(to_function_helper(impl));
}
private:
any_function() {}
struct impl_type
{
virtual ~impl_type() {}
virtual boost::any invoke(const boost::any&) = 0;
};
boost::shared_ptr<impl_type> impl;
template <typename Res, typename Arg>
static impl_type* make_impl(boost::function<Res(Arg)> f)
{
using boost::function;
using boost::any;
using boost::any_cast;
class impl : public impl_type
{
function<Res(Arg)> f;
any invoke(const any& x)
{
const Arg& a = any_cast<Arg>(x);
return any(f(a));
}
public:
impl(function<Res(Arg)> f) : f(f) {}
};
return new impl(f);
}
impl_type* compose_impl(boost::shared_ptr<impl_type> f,
boost::shared_ptr<impl_type> g)
{
using boost::any;
using boost::shared_ptr;
class impl : public impl_type
{
shared_ptr<impl> f, g;
any invoke(const any& x)
{
return g->invoke(f->invoke(x));
}
public:
impl(const shared_ptr<impl>& f,
const shared_ptr<impl>& g)
: f(f), g(g)
{}
};
return new impl(f, g);
}
struct to_function_helper
{
template <typename Res, typename Arg>
Res operator()(const Arg& x)
{
using boost::any;
using boost::any_cast;
return any_cast<Res>(p->invoke(any(x)));
}
to_function_helper(const boost::shared_ptr<impl>& p) : p(p) {}
private:
boost::shared_ptr<impl> p;
};
};
Now, let's use standard algorithms and do this (this even works on empty sequences):
// First function passed is evaluated first. Feel free to change.
template <typename Arg, typename Res, typename I>
boost::function<Res(Arg)> pipeline(I begin, I end)
{
return std::accumulate(begin, end,
any_function::id<Arg>,
std::ptr_fun(any_function::compose)
).to_function<Res, Arg>();
}
and use the following to apply it
std::vector<any_function> f;
std::vector<double> v;
std::vector<int> result;
std::transform(v.begin(), v.end(),
result.begin(),
pipeline<double, int>(f.begin(), f.end())
);
You can even use boost::transform_iterator
typedef boost::transform_iterator<
boost::function<double, int>,
std::vector<double>::const_iterator
> iterator;
boost::function<double, int> f = pipeline<double, int>(f.begin(), f.end());
std::copy(iterator(v.begin(), f), iterator(v.end(), f), result.begin());
template<class T>
class compose {
typedef T (*f)(T);
f first_func;
f second_func;
public:
compose(f one,f two) :
first_func(one),
second_func(two)
{}
T operator()(T const &input) {
T temp = first_func(input);
return second_func(temp);
}
};
#ifdef TEST
int f(int x) { return 8 + x; }
int g(int x) { return 2 * x; }
int h(int x) { return x * x; }
#include <iostream>
int main(int argc, char **argv) {
compose<int> x(f, g);
compose<int> y(g, f);
std::cout << x(6) << std::endl;
std::cout << y(6) << std::endl;
typedef int (*func)(int);
func funcs[] = {f, g, h};
compose<int> z(funcs[atoi(argv[1])], funcs[atoi(argv[2])]);
std::cout << z(6);
return 0;
}
#endif
With C++0x, we should be able to use auto to eliminate having to specify the argument/return type. For the moment I've assumed they're the same, though in theory, you might like the ability to include conversions in the mix.
you should use a functor instead of function and pass needed transform functions into functor's constructor
something like
typedef int (*FunctionType)(int);
class Functor
{
FunctionType m_f1;
FunctionType m_f2;
FunctionType m_f3;
public:
Functor(FunctionType f1, FunctionType f2, FunctionType f3):
m_f1(f1), m_f2(f2), m_f3(f3)
{}
int operator()(int n)
{
return (*m_f1)((*m_f2)((*m_f3)(n)));
}
};
// ...
transform(source.begin(), source.end(), back_inserter(temp1), Functor(f1,f2,f3));
if you need variable number of functions then change Functor constructor signature to use vector of functions and fill that vector before calling transform.
Just define an iterator that does what you want:
template<typename T>
struct source
{
virtual source<T>& operator++(void) = 0;
virtual T operator*(void) = 0;
virtual bool atend() = 0;
};
struct source_exhausted
{
};
template<typename T>
bool operator==(const source<T>& comparand, const source_exhausted&)
{ return comparand.atend(); }
template<typename T>
bool operator!=(const source<T>& comparand, const source_exhausted&)
{ return !comparand.atend(); }
template<typename T>
bool operator==(const source_exhausted&, const source<T>& comparand)
{ return comparand.atend(); }
template<typename T>
bool operator!=(const source_exhausted&, const source<T>& comparand)
{ return !comparand.atend(); }
template<typename T, typename iterT, typename endT>
struct source_iterator : source<T>
{
iterT m_iter;
endT m_end;
source_iterator(iterT iter, endT end) : m_iter(iter), m_end(end) {}
virtual source<T>& operator++(void) { ++m_iter; return *this; }
virtual T operator*(void) { return *m_iter; }
virtual bool atend() { return m_iter == m_end; }
};
template<typename T, typename iterT, typename endT>
auto make_source_iterator(iterT iter, endT end) -> source_iterator<decltype(*iter), iterT, endT>
{
return source_iterator<decltype(*iter), iterT, endT>(iter, end);
}
template<typename TContainer>
auto make_source_iterator(TContainer& c) -> source_iterator<typename TContainer::value_type, decltype(c.begin()), decltype(c.end())>
{
return source_iterator<typename TContainer::value_type, decltype(c.begin()), decltype(c.end())>(c.begin(), c.end());
}
template<typename TIn, typename TOut, typename TXform>
struct source_transformer : source<TOut>
{
source<TIn>& m_src;
TXform const m_f;
source_transformer( source<TIn>& src, TXform f ) : m_f(f), m_src(src) {}
virtual source<TOut>& operator++(void) { ++m_src; return *this; }
virtual TOut operator*(void) { return m_f(*m_src); }
virtual bool atend() { return m_src.atend(); }
};
template<typename TIn, typename TOut, typename TXform>
auto make_source_transformer(source<TIn>& src, TXform f) -> source_transformer<TIn, decltype(f(*(TIn*)0)), TXform>
{
return source_transformer<TIn, decltype(f(*(TIn*)0)), TXform>(src, f);
}
typedef int (*f_t)(int);
int f1(int a) { return a + 1; }
int f2(int a) { return a * 2; }
int f3(int a) { return a * a; }
int main()
{
std::vector<f_t> ff = {f1, f2, f3};
std::vector<int> source = {1, 2, 3, 4}, target;
std::transform(source.begin(), source.end(), std::back_inserter(target)
, [&](int a) { for (f_t &f : ff) a = f(a); return a; });
// print target
std::copy(target.begin(), target.end(), std::ostream_iterator<int,char>(std::cout,"\n"));
system("pause");
return 0;
}