Let's say i have a class that simply performs addition for any type T. I want to add an optional range check (based on a template parameter of type bool), that will check whether the result of the addition belongs in a given range, or else it will throw.
One way of doing this, is wrapping all basics of the class in a base class and then specialize on the boolean template parameter. Something like:
// The base class; holds a starting value to add to and a maximum value
template<typename T>
class DummyImpl
{
private:
T mval, mmax;
public:
constexpr explicit DummyImpl(T x, T max_x) noexcept
: mval{x}, mmax{max_x}
{};
// base class; use a virtual destructor
virtual ~DummyImpl() {};
T max() const noexcept {return mmax;}
T val() const noexcept {return mval;}
};
// The "real" class; parameter B denotes if we want (or not)
// a range check
template<typename T, bool B>
class Dummy : DummyImpl<T> {};
// Specialize: we do want range check; if sum not in range
// throw.
template<typename T>
class Dummy<T, true> : DummyImpl<T>
{
public:
explicit Dummy(T x, T max_x) noexcept : DummyImpl<T>(x, max_x) {};
T add(T x) const noexcept( !true )
{
T ret_val = x + DummyImpl<T>::val();
if (ret_val < 0 || ret_val > DummyImpl<T>::max()) {
throw 1;
}
return ret_val;
}
};
// Specialize for no range check.
template<typename T>
class Dummy<T, false> : DummyImpl<T>
{
public:
explicit Dummy(T x, T max_x) noexcept : DummyImpl<T>(x, max_x) {};
T add(T x) const noexcept( !false )
{
return x + DummyImpl<T>::val();
}
};
Now the user can write code like:
int main()
{
Dummy<float,false> d(0, 1000); //no range check; never throw
std::cout <<"\nAdding 156.7 gives " << d.add(156.7);
std::cout <<"\nAdding 3156.7 gives " << d.add(3156.7);
std::cout <<"\n";
return 0;
}
Is there a way of doing this without using inheritance? I would suppose that using a nested class would be more efficient, but the following code
does not compile.
template<typename T, bool RC>
class Dummy
{
private:
T mval, mmax;
// parameter S is only used to enable partial specialization on
// parameter I
template<bool I, typename S> struct add_impl {};
template<typename S> struct add_impl<true, S>
{
T operator()(T x) const noexcept( !true )
{
T ret_val = x + mval;
if (ret_val < 0 || ret_val > mmax) {throw 1;}
return ret_val;
}
};
template<typename S> struct add_impl<false, S>
{
T operator()(T x) const noexcept( !false )
{
return x + mval_ref;
}
};
public:
constexpr explicit Dummy(T x, T max_x) noexcept
: mval{x}, mmax{max_x}
{};
void bar() const { std::cout << "\nin Base."; }
T max() const noexcept {return mmax;}
T val() const noexcept {return mval;}
T add(T x) const noexcept( !RC )
{
return add_impl<RC, T>()(x);
}
};
int main()
{
Dummy<float,false> d(0, 1000);
std::cout <<"\nAdding 156.7 gives " << d.add(156.7);
std::cout <<"\nAdding 3156.7 gives " << d.add(3156.7);
std::cout <<"\n";
return 0;
}
It fails with an error message (in g++):
error: invalid use of non-static data member ‘Dummy<float, false>::mval’
Is there a way around this? If so, is it more efficient than the first solution? Will the nested class add size to any instance of Dummy? Is there a more elegant design/implementation?
I would just dispatch on RC. And making it a type:
template<typename T, bool RC>
class Dummy
{
private:
using do_range_check = std::integral_constant<bool, RC>;
T mval, mmax;
};
With that:
T add(T x) const {
return add(x, do_range_check{});
}
private:
T add(T x, std::false_type /* range_check */) {
return x + mval;
}
T add(T x, std::true_type /* range_check */) {
T ret_val = x + mval;
if (ret_val < 0 || ret_val > mmax) {throw 1;}
return ret_val;
}
The advantage there is that this is a normal member function - you're not offloading onto some other type that you need to pass members around to. And you don't need to specialize... anything. Which is great.
I usually try to not use boolean flags in functions to switch behavior.
You can pass the range-check as a policy instead of the bool template parameter, in the style of policy-based design. The policies do not need a be related by inheritance, because there are no constraints on the type of the template arguments except the ones derived from using them. You can put in any type you like as long as it provides the necessary interface. This way, I can define two independent classes without any (inheritance) relationship, and use both of them as template parameters. The drawback is that Dummy<float, X> and Dummy<float, Y> are two different, unrelated types and you cannot e.g. assign an instance of the first type to an instance of the second one without defining a template assignment operator.
#include <stdexcept>
template<typename T>
struct NoMaxCheck
{
NoMaxCheck(T) {}
void check(T) const noexcept {}
};
template<typename T>
struct ThresholdChecker
{
ThresholdChecker(T value) : mMax(value) {}
void check(T value) const
{
if (value < 0 || mMax < value) {
throw std::out_of_range("");
}
}
private:
T mMax;
};
template<typename T, typename CheckPolicy>
class Dummy
{
private:
T mVal;
CheckPolicy mThresholdChecker;
public:
explicit Dummy(T x, T max_x) noexcept : mVal(x), mThresholdChecker(max_x) {};
T add(T x) const noexcept(noexcept(mThresholdChecker.check(x)))
{
T ret_val = x + mVal();
mThresholdChecker.check(ret_val);
return ret_val;
}
};
template<typename T, template<typename> typename CheckPolicy>
class DummyEmptyBaseClasss: private CheckPolicy<T>
{
private:
T mVal;
public:
explicit DummyEmptyBaseClasss(T x, T max_x) noexcept:
CheckPolicy<T>(max_x),
mVal(x) {};
T add(T x) const noexcept(noexcept(check(x)))
{
T ret_val = x + mVal();
check(ret_val);
return ret_val;
}
};
int foo()
{
Dummy<float,NoMaxCheck<float>> unchecked(0, 1000);
Dummy<float,ThresholdChecker<float>> checked(0, 1000);
static_assert( sizeof(DummyEmptyBaseClasss<float, NoMaxCheck>) == sizeof(float), "empty base class optimization");
}
You can simplify it more with template-template parameters to get rid of the redundant float parameter. DummyEmptyBaseClass shows this.
Compilers are quite good at elimination of obviously dead code (such as that arising from boolean template parameters). I'd therefore go with the most straightforward solution:
template<typename T, bool RC>
class Dummy
{
private:
T mval, mmax;
public:
T add(T x) const noexcept( !RC )
{
T ret_val = x + val();
if (RC && (ret_val < 0 || ret_val > DummyImpl<T>::max())) {
throw 1;
}
return ret_val;
}
//...
};
I would be extremely surprised if any runtime code were generated for the instantiation where RC == false. In fact, I would consider that an optimiser bug.
You may use composition
template<typename T, bool B> struct ThresholdChecker;
template<typename T>
struct ThresholdChecker<T, true>
{
ThresholdChecker(T value) : mMax(value) {}
void check(T value) const
{
if (value < 0 || mMax < value) {
throw std::out_of_range("");
}
}
private:
T mMax;
};
template<typename T>
struct ThresholdChecker<T, false>
{
ThresholdChecker(T) {}
void check(T) const noexcept {}
};
template<typename T, bool RC>
class Dummy
{
private:
T mval;
ThresholdChecker<T, RC> mThresholdChecker;
public:
explicit Dummy(T x, T max_x) noexcept : mVal(x), mThresholdChecker(max_x) {};
T add(T x) const noexcept(noexcept(mThresholdChecker.check(x)))
{
T ret_val = x + val();
mThresholdChecker.check(ret_val);
return ret_val;
}
//...
};
Related
I have a templated class
template <typename T>
class SometimesComparable
{
public:
T x1;
T x2;
// Other functionally provided unconditionally
// ...
// To be provided only if T provides operator<
// bool operator<(SometimesComparable const & other) const
// {
// return x1 < other.x1 && x2 < other.x2;
// }
};
that should provide bool operator<() if and only if its template parameter also provides bool operator<()
I have read similar questions/answers that use SFINAE but there must be something I didn't understand because I didn't manage to adapt the idea to this case.
Imitating those answers I have a class
template <typename T>
class HasLessThan
{
private:
typedef char YesType[1];
typedef char NoType[2];
template <typename C> static YesType& test( decltype(&C::operator<) );
template <typename C> static NoType& test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
};
to detect, using its method test via its member value, whether a class T provides operator<.
Inside the SometimesComparable class I am defining
typename std::enable_if<HasLessThan<T>::value, bool>::type
operator<(ConditionalMethodProvided &other)
{
return x1 < other.x1 && x2 < other.x2;
}
Then, for testing, for a use that works I have a class
class TypeWithLessThan
{
public:
int x;
TypeWithLessThan(int x) : x(x) {};
bool operator<(TypeWithLessThan &other) {return x < other.x;};
};
int main(int argc, char *argv[])
{
ConditionalMethodProvided C(TypeWithLessThan(2), TypeWithLessThan(3));
ConditionalMethodProvided D(TypeWithLessThan(5), TypeWithLessThan(7));
std::cout << (C < D) << std::endl;
return 0;
}
Question part: This is fine. Now, what I am missing is how should be the implementation such that
int main(int argc, char *argv[])
{
ConditionalMethodProvided C(2, 3);
ConditionalMethodProvided D(5, 7);
std::cout << (C < D) << std::endl;
return 0;
}
also compiles successfully.
I tried adding to SometimesComparable a friend method
friend
typename std::enable_if<HasLessThan<T>::value, bool>::type
operator<(ConditionalMethodProvided & a1, ConditionalMethodProvided &a2)
{
return a1.x1 < a2.x1 && a1.x2 < a2.x2;
};
Having both the first operator< and the friend one, creates an ambiguous overload, not having it causes the comparison of ConditionalMethodProvided<int, int> to not compile.
I would like both int and TypeWithLessThan to work.
Edit:
The code in a single block.
#include <iostream>
#include <type_traits>
template <typename T>
class HasLessThan
{
private:
typedef char YesType[1];
typedef char NoType[2];
template <typename C> static YesType& test( decltype(&C::operator<) );
template <typename C> static NoType& test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
};
template <typename T>
class ConditionalMethodProvided
{
public:
T x1;
T x2;
ConditionalMethodProvided(T&& a1, T&& a2) : x1(a1), x2(a2) {};
// This and the next method may not be needed at the same time.
typename std::enable_if<HasLessThan<T>::value, bool>::type
operator<(ConditionalMethodProvided &other)
{
return x1 < other.x1 && x2 < other.x2;
};
template <typename U,
std::enable_if_t<std::is_same_v<U, T>, bool> = true>
auto operator< (ConditionalMethodProvided<U> & oth)
-> decltype( std::declval<U>() < std::declval<U>(), bool{} )
{ return x1 < oth.x1 && x2 < oth.x2; }
};
class TypeWithLessThan
{
public:
int x;
TypeWithLessThan(int x) : x(x) {};
bool operator<(TypeWithLessThan &other) {return x < other.x;};
};
int main(int argc, char *argv[])
{
// The question is how to to make the next two types, int and TypewithLessThan both make the templated class ConditionalMethodProvided to provide the operator< method.
ConditionalMethodProvided C(TypeWithLessThan(2), TypeWithLessThan(3));
ConditionalMethodProvided D(TypeWithLessThan(5), TypeWithLessThan(7));
std::cout << (C < D) << std::endl;
ConditionalMethodProvided E(2,3);
ConditionalMethodProvided F(5,7);
std::cout << (E < F) << std::endl;
return 0;
}
What about as follows ?
template <typename T>
class SometimesComparable
{
public:
T x1;
T x2;
template <typename U,
std::enable_if_t<std::is_same_v<U, T>, bool> = true>
auto operator< (SometimesComparable<U> const & oth)
-> decltype( x1 < oth.x1, bool{} )
{ return x1 < oth.x1 && x2 < oth.x2; }
};
I mean... if you want SFINAE enable/disable a method, you have to make the method a template one, so
template <typename U>
bool operator< (SometimesComparable<U> const & oth)
{ /* something */ }
but I suppose you want that U and T are the same type, so you can impose this throug std::enable_if_t
template <typename U,
std::enable_if_t<std::is_same_v<U, T>, bool> = true>
bool operator< (SometimesComparable<U> const & oth)
{ /* something */ }
Now you have to SFINAE enable the operator iff (if and only if) you can write x1 < oth.x1 (when the operator is defined for U) so, using auto, trailing return type and decltype(), you can write
auto operator< (SometimesComparable<U> const & oth)
-> decltype( x1 < oth.x1, bool{} )
{ /* something */ }
or also simply decltype( x1 < oth.x1 ) if you're sure that x1 < oth.x1 gives a bool value.
For future reference, you can write this in C++20 concepts:
// To be provided only if T provides operator<
auto operator<(SometimesComparable const & other) const -> bool
requires requires(T a, T b) {
{a < b} -> bool;
}
{
return x1 < other.x1 && x2 < other.x2;
}
I am trying to find a way to compare boost::variant with underlying value without constructing variant from this underlying value. The question is defined in the comment in "main()" function
And auxiliary question is about the comparison operators defined in the code. How to decrease the # of comparison operators? If boost::variant contains, say, 6 different types, do I have to define 6! operators to be able to compare two variants?
Thanks!
#include <boost/variant.hpp>
namespace test {
namespace Tag {
struct Level1{ int t{ 1 }; };
struct Level2{ int t{ 2 }; };
}
template <typename Kind> struct Node;
using LevelOne = Node<Tag::Level1>;
using LevelTwo = Node<Tag::Level2>;
using VariantNode = boost::variant
<
boost::recursive_wrapper<LevelOne>,
boost::recursive_wrapper<LevelTwo>
>;
typedef VariantNode* pTree;
typedef std::vector<pTree> lstTree;
template <typename Kind> struct Node
{
Node(pTree p, std::string n) : parent(p), name(n) {}
Node(const Node& another) : name(another.name), parent(another.parent) {}
virtual ~Node() {}
std::string name;
pTree parent;
};
bool operator == (const LevelOne& one, const LevelTwo& two) {
return false;
}
bool operator == (const LevelTwo& two, const LevelOne& one) {
return false;
}
bool operator == (const LevelOne& one, const LevelOne& two) {
return true;
}
bool operator == (const LevelTwo& one, const LevelTwo& two) {
return true;
}
}
int main(int argc, char *argv[])
{
using namespace test;
LevelOne l1(nullptr, "level one");
VariantNode tl2 = VariantNode(LevelTwo(nullptr, "level two"));
VariantNode tl1 = VariantNode(LevelOne(nullptr, "level one"));
bool rv = (tl1 == tl2); // this line compiles OK (comparing two variants)
// comparison below does not compile, because "l1" is not a variant.
// Question: How can I compare "variant" value "tl1"
// with one of the possible content values "l1"
bool rv1 = (tl1 == l1);
return 1;
}
The following will work with any number of types in the variant:
template<typename T>
struct equality_visitor : boost::static_visitor<bool> {
explicit constexpr equality_visitor(T const& t) noexcept : t_{ &t } { }
template<typename U, std::enable_if_t<std::is_same<T, U>::value>* = nullptr>
constexpr bool operator ()(U const& u) const {
return *t_ == u;
}
template<typename U, std::enable_if_t<!std::is_same<T, U>::value>* = nullptr>
constexpr bool operator ()(U const&) const {
return false;
}
private:
T const* t_;
};
template<
typename T,
typename... Ts,
typename = std::enable_if_t<
boost::mpl::contains<typename boost::variant<Ts...>::types, T>::value
>
>
bool operator ==(T const& t, boost::variant<Ts...> const& v) {
equality_visitor<T> ev{ t };
return v.apply_visitor(ev);
}
template<
typename T,
typename... Ts,
typename = std::enable_if_t<
boost::mpl::contains<typename boost::variant<Ts...>::types, T>::value
>
>
bool operator !=(T const& t, boost::variant<Ts...> const& v) {
return !(t == v);
}
The catch is that comparisons must always be of the form value == variant or value != variant rather than variant == value or variant != value. This is because boost::variant<> itself defines these operators to always static_assert, and there is no way for us to make a global operator more specialized than variant<>'s built-in ones.
Online Demo
I'm trying to implement a container class for different functions where I can hold function pointers and use it to call those functions later. I'll try to discribe my problem more accurate.
As example, I have 2 different test functions:
int func1(int a, int b) {
printf("func1 works! %i %i\n", a, b);
return 0;
}
void func2(double a, double b) {
printf("func2 works! %.2lf %.2lf\n", a, b);
}
and I also have array of variants, which holds function arguments:
std::vector<boost::variant<int, double>> args = {2.2, 3.3};
I've decided to use my own functor class derived from some base class ( I thought about using virtual methods):
class BaseFunc {
public:
BaseFunc() {}
~BaseFunc() {}
};
template <typename T>
class Func;
template <typename R, typename... Tn>
class Func<R(Tn...)> : public BaseFunc {
typedef R(*fptr_t)(Tn...);
fptr_t fptr;
public:
Func() : fptr(nullptr) {}
Func(fptr_t f) : fptr(f) {}
R operator()(Tn... args) {
return fptr(args...);
}
Func& operator=(fptr_t f) {
fptr = f;
return *this;
}
};
Also I've decided to store some information about function and its arguments:
struct TypeInfo {
int type_id; // for this example: 0 - int, 1 - double
template <class T>
void ObtainType() {
if (std::is_same<void, T>::value)
type_id = 0;
else if (std::is_same<int, T>::value)
type_id = 1;
else if (std::is_same<double, T>::value)
type_id = 2;
else
type_id = -1;
}
};
struct FunctionInfo {
public:
FunctionInfo() {}
FunctionInfo(BaseFunc *func, const TypeInfo& ret, std::vector<TypeInfo>& args) :
func_ptr(func), return_info(ret)
{
args_info.swap(args);
}
~FunctionInfo() {
delete func_ptr;
}
BaseFunc * func_ptr;
TypeInfo return_info;
std::vector<TypeInfo> args_info;
};
So now I can define a container class:
class Container {
private:
template <size_t n, typename... T>
void ObtainTypeImpl(size_t i, TypeInfo& t)
{
if (i == n)
t.ObtainType<std::tuple_element<n, std::tuple<T...>>::type>();
else if (n == sizeof...(T)-1)
throw std::out_of_range("Tuple element out of range.");
else
ObtainTypeImpl<(n < sizeof...(T)-1 ? n + 1 : 0), T...>(i, t);
}
template <typename... T>
void ObtainType(size_t i, TypeInfo& t)
{
return ObtainTypeImpl<0, T...>(i, t);
}
public:
template <class R, class ...Args>
void AddFunc(const std::string& str, R(*func)(Args...)) {
BaseFunc * func_ptr = new Func<R(Args...)>(func);
size_t arity = sizeof...(Args);
TypeInfo ret;
ret.ObtainType<R>();
std::vector<TypeInfo> args;
args.resize(arity);
for (size_t i = 0; i < arity; ++i)
{
ObtainType<Args...>(i, args[i]);
}
cont_[str] = FunctionInfo(func_ptr, ret, args);
}
void CallFunc(const std::string& func_name,
std::vector<boost::variant<int, double>>& args_vec) {
auto it = cont_.find(func_name);
if (it != cont_.end())
{
// ???????
// And here I stucked
}
}
private:
std::map<std::string, FunctionInfo> cont_;
};
And then I stucked.
Don't know how to get function type information from my struct :).
Don't know how to convert vector of variants to arguments list.
Maybe my path was wrong? Can you suggest any solution of this problem except script engine like Lua?
You may do something like:
class BaseFunc {
public:
virtual ~BaseFunc() = default;
virtual void Call(std::vector<boost::variant<int, double>>& args_vec) const = 0;
};
template <typename F> class Function;
template <typename R, typename... Args> class Function<R(Args...)> : public BaseFunc
{
public:
Function(R (*f)(Args...)) : f(f) {}
void Call(std::vector<boost::variant<int, double>>& args_vec) const override
{
Call(args_vec, std::index_sequence_for<Args...>());
}
private:
template <std::size_t ... Is>
void Call(
std::vector<boost::variant<int, double>>& args_vec,
std::index_sequence<Is...>) const
{
// Add additional check here if you want.
f(boost::get<Args>(args_vec.at(Is))...);
}
private:
R (*f)(Args...);
};
Live example
I've had a scan for answers but ... they seem to be silly questions.
I am perfectly happy with and fully understand (I can't stress that enough) with why it makes no sense to have a template virtual member of a class.
Consider the abstract base class List (With... LinkedList and ArrayList deriving from it)
If the type the list stores has a concept of identity (not a string or int, something without any sensible "==", I wont bring POD up here) you would want a method
virtual bool contains(T& what) const; and
virtual int index(T& what) const;
however if it is a type without identity, like strings or numbers you would want:
virtual int countOccurrences(T& what) const; and
virtual int find(T& what, int occurrence=0) const;
Say.
This cannot be done using ::std::enable_if so you must do something like:
template<class T, bool HAS_IDENTITY> class List;
template<class T> class List<false> {
virtual int countOccurrences(T& what) const=0;
virtual int find(T& what, int occurrence=0) const=0;
/*other stuff*/
};
template<class T> class List<true> {
virtual bool contains(T& what) const =0;
virtual int index(T& what) const =0;
/*other stuff*/
};
This isn't that bad, but there is a lot of code duplication, and I only get wet (against DRY) when I have to.
If I hide the common code in a base class it is a bit nicer.
My question involves scaling with this approach, here we have one bool, giving 2 specialisations, suppose I have n bools then there are 2^n specialisations, I can't see a case where I'd need more than 4, but that is still 16 classes involved! 8 for 3, it's not very nice.
Suppose I have an enum and a bool, then I have 2*enum count specialisations.
It grows far to quickly.
Previously we've used macros to define classes and it'd use the ## operator in the class name to essentially mangle it as a template would. I must say though I quite like enable_if and friends now though...
Is there a pattern someone can show me that'd solve this?
You may use template policies:
template<class T, bool HAS_IDENTITY> class ListIdentityPolicy;
template<class T> class ListIdentityPolicy<T, false> {
virtual int countOccurrences(T& what) const = 0;
virtual int find(T& what, int occurrence = 0) const = 0;
};
template<class T> class ListIdentityPolicy<T, true> {
virtual bool contains(T& what) const = 0;
virtual int index(T& what) const = 0;
};
template<class T, bool HAS_FOOBAR> struct ListFoobarPolicy;
template<class T> struct ListFoobarPolicy<T, false> {
virtual void foo() = 0;
};
template<class T> struct ListFoobarPolicy<T, true> {
virtual void bar() = 0;
};
template <class T> class List
: public ListIdentityPolicy<T, HasIdentity<T>::value>
, public ListFoobarPolicy<T, HasFoobar<T>::value>
{
public:
/*other stuff*/
};
HasIdentity and HasFoobar are type traits which you would define, each containing a static const bool value indicating whether T has the corresponding property.
Or, you could give List a non-virtual public API, and hide the dynamic dispatch in the implementation:
template <class T> class List
{
public:
enum Impl {
LinkedList = 0,
ArrayList,
};
List(Impl i) : pimpl(makePimpl(i)) {}
List(List const& other) : pimpl(other.pimpl->clone())
List& operator=(List const& other) { pimpl = other.pimpl->clone(); }
int count(T& what) const
{ static_assert(! HasIdentity<T>::value, "oops"); return pimpl->count(what); }
int find(T& what, int n = 0) const
{ static_assert(! HasIdentity<T>::value, "oops"); return pimpl->find(what, n); }
bool contains(T& what) const
{ static_assert(HasIdentity<T>::value, "oops"); return pimpl->contains(what); }
int index(T& what) const
{ static_assert(HasIdentity<T>::value, "oops"); return pimpl->index(what); }
void foo()
{ static_assert(! HasFoobar<T>::value, "oops"); pimpl->foo(); }
void bar()
{ static_assert(HasFoobar<T>::value, "oops"); pimpl->bar(); }
private:
struct AbstractPimpl
{
virtual std::unique_ptr<AbstractPimpl> clone() const = 0;
virtual int count(T& what) const = 0;
virtual int find(T& what, int n = 0) const = 0;
virtual bool contains(T& what) const = 0;
virtual int index(T& what) const = 0;
virtual void foo() = 0;
virtual void bar() = 0;
};
struct LinkedListPimpl : public AbstractPimpl
{
std::unique_ptr<AbstractPimpl> clone() override;
int count(T& what) const override;
int find(T& what, int n = 0) const override;
bool contains(T& what) const override;
int index(T& what) const override;
void foo() override;
void bar() override;
/* ... */
};
struct ArrayListPimpl : public AbstractPimpl
{
std::unique_ptr<AbstractPimpl> clone() override;
virtual int count(T& what) const override;
virtual int find(T& what, int n = 0) const override;
virtual bool contains(T& what) const override;
virtual int index(T& what) const override;
virtual void foo() override;
virtual void bar() override;
/* ... */
};
std::unique_ptr<AbstractPimpl> pimpl;
static std::unique_ptr<AbstractPimpl> makePimpl(Impl i) {
switch (i) {
LinkedList: default:
return std::make_unique<LinkedListPimpl>();
ArrayList:
return std::make_unique<ArrayListPimpl>();
}
}
};
Just a q&d hack, but it should provide some hints.
I somehow know that one could even get rid of that ugly "Dummy" param, but I don't see that right now
EDIT Jul 6th
I made that ansatz a little more seamless to use.
A compile-time test of the Concept "Identity", what the question opener is apparently aiming at, would require compile-time testing of
//T t1, t2;
(t1 == t2) == (&t1 == &t2);
and that is imo not possible.
Thus I introduced the notion of Feature lists for easy manual assignment of such features.
#include <iostream>
#include <typeinfo>
#include <type_traits>
#ifdef __GNUG__
#include <cxxabi.h>
auto type_str = [](const std::type_info& ti) {
int stat;
return abi::__cxa_demangle(ti.name(), 0, 0, &stat);
};
#else
#warning untested
auto type_str = [](const std::type_info& ti) {
return ti.name();
};
#endif
typedef int Feature;
const Feature HAS_IDENTITY = 1;
const Feature HAS_FOOBAR = 2;
const Feature HAS_NO_IDENTITY = -HAS_IDENTITY;
const Feature HAS_NO_FOOBAR = -HAS_FOOBAR;
const Feature _TERM_ = 0;
template<typename T, Feature F>
struct has_feature : std::false_type {};
template<int N , int M>
struct is_greater {
constexpr static bool value = N > M;
};
namespace detail {
template<class T, Feature... Fs> struct List {}; // primary template
template<class T, Feature F>
struct List<T,F> {};
template<class T, Feature F, Feature... Fs>
struct List<T,F,Fs...>
: virtual public
std::conditional<
has_feature<T,F>::value,
List<T, F>,
List<T, -F>
>::type,
virtual public
std::conditional<
is_greater<sizeof...(Fs),0>::value,
List<T, Fs...>,
List<T, _TERM_>
> ::type {};
template<class T> struct List<T, _TERM_> {};
template<class T>
struct List<T,HAS_NO_FOOBAR> {
virtual std::string hello() const /* = 0;*/ {
return std::string("\"What the foo is FOOBAR?\", askes ") + type_str(typeid(T));
}
};
template<class T>
struct List<T,HAS_FOOBAR> {
virtual std::string hello() const /* = 0;*/ {
return std::string("\"For sure I'm FOOBAR\", says ") + type_str(typeid(T));
}
};
template<class T>
struct List<T,HAS_NO_IDENTITY> {
virtual int index(const T& what) const /* = 0;*/ {
return 137;
}
};
template<class T>
struct List<T,HAS_IDENTITY> {
virtual int index(const T& what) const /* = 0;*/ {
return 42;
}
};
template<typename T>
using Feature_Aware_List = List<T,HAS_IDENTITY,HAS_FOOBAR, /* all Features incuding*/_TERM_>;
} //namespace detail
template<typename T>
using List = detail::Feature_Aware_List<T>;
struct Gadget {
bool operator== (const Gadget& rhs) const {
return this == &rhs;
}
};
struct Gimmick {
bool operator== (const Gimmick& rhs) const {
return this == &rhs;
}
};
template<Feature F>
struct FeatureList {};
template<>
struct FeatureList<HAS_IDENTITY>
: public Gadget,
public Gimmick
/**/
{};
#include <valarray>
template<>
struct FeatureList<HAS_FOOBAR>
: public std::valarray<float>
/**/
{};
template<class T>
struct has_feature<T, HAS_IDENTITY>
: public std::conditional<
std::is_base_of<T, FeatureList<HAS_IDENTITY>>::value,
std::true_type,
std::false_type
>::type {};
template<class T>
struct has_feature<T, HAS_FOOBAR>
: public std::conditional<
std::is_base_of<T, FeatureList<HAS_FOOBAR>>::value,
std::true_type,
std::false_type
>::type {};
int main() {
List<Gadget> l1 ;
List<std::valarray<float>> l2;
std::cout << l1.hello() << " #" << l1.index(Gadget()) << std::endl;
std::cout << l2.hello() << " #" << l2.index(std::valarray<float>()) << std::endl;
}
Output:
"What the foo is FOOBAR?", askes Gadget #42
"For sure I'm FOOBAR", says std::valarray<float> #137
It should be self-explaining that no specific "list" functionality is implemented, that's mock-only
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;
}