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
Related
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;
}
//...
};
Because the following is illegal:
struct A {
template <typename T>
virtual T* foo() = 0;
};
struct B : A {
template <typename T>
virtual T* foo() override {return new T;} // Simple example here.
};
template <typename T>
T* bar (A* a) {
return a->foo<T>(); // The need for the virtual method.
}
and the template only appears in the return type, I've thought of a (naïve?) workaround using overload:
#include <iostream>
struct Base { virtual void show() const = 0; };
struct Object : Base { virtual void show() const override {std::cout << "I am an Object.\n";} };
struct Thing : Base { virtual void show() const override {std::cout << "I am a Thing.\n";} };
struct Blob : Base { virtual void show() const override {std::cout << "I am a Blob.\n";} };
struct A {
virtual Object* foo (Object&&) = 0;
virtual Thing* foo (Thing&&) = 0;
virtual Blob* foo (Blob&&) = 0;
};
struct B : A {
virtual Object* foo (Object&&) override {return fooHelper<Object>();}
virtual Thing* foo (Thing&&) override {return fooHelper<Thing>();}
virtual Blob* foo (Blob&&) override {return fooHelper<Blob>();}
private:
template <typename T>
T* fooHelper() {return new T;} // Simple example here.
};
template <typename T>
T* bar (A* a) {
return a->foo(T{});
}
int main() {
B* b = new B;
Base* list[] = {bar<Object>(b), bar<Thing>(b), bar<Blob>(b)};
for (const Base* x : list) x->show();
}
The problem with this solution is that it is only feasible if there are not too many types for T. But what if there are? Furthermore, there is now the maintenance problem when new types for T are introduced later.
Can someone think of a better solution than this? The known visitor pattern as a virtual template workaround does not apply here (I don't think) because the template does not appear in the argument.
...
T* fooHelper() {return new T;}
};
template <typename T>
T* create (A* a) {
return a->foo(T{});
}
The instance of A has no effect on the T you return. I'm assuming maybe that's supposed to be an argument. It also seems like you want a factory. How about using a member function:
template < typename T, typename FactoryType,
typename MemFnType, typename ArgType >
T* create(FactoryType* f, MemFnType mfn, ArgType a)
{
return (f->*mfn)(a);
}
Full Example:
#include <iostream>
struct Base { virtual void show() const = 0; };
struct Object : Base { virtual void show() const override {std::cout << "I am an Object.\n";} };
struct Thing : Base { virtual void show() const override {std::cout << "I am a Thing.\n";} };
struct Blob : Base { virtual void show() const override {std::cout << "I am a Blob.\n";} };
struct Args
{
int someArg;
};
struct Factory
{
// normally 'a' would be passed to the Object constructor.
// omitted to save edits.
Object* asObject(const Args& a) { return new Object(); }
Thing* asThing(const Args& a) { return new Thing(); }
Blob* asBlob(const Args& a) { return new Blob(); }
};
template < typename T, typename FactoryType,
typename MemFnType, typename ArgType >
T* create(FactoryType& f, MemFnType mfn, ArgType& a)
{
return (&f->*mfn)(a);
}
int main() {
Args arg;
Factory f;
Base* list[] = {create<Object>(f, &Factory::asObject, arg), create<Thing>(f, &Factory::asThing, arg), create<Blob>(f, &Factory::asBlob, arg)};
for (const Base* x : list) x->show();
}
Adding constructible types just requires adding the type itself and the related factory function. You can even generalize it to a full template argument list instead of a single argument type.
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 want to be able to get the size of polymorphic object. At the moment I got this:
struct Base {
virtual std::size_t size() const {
return sizeof(*this);
}
};
struct Derived : Base {
virtual std::size_t size() const {
return sizeof(*this);
}
};
Which is literally copy & paste. I want to do better. Suppose I really hate macros and CRTP seems like the only sensible approach. Let us give it a try:
struct SizedBase {
virtual std::size_t size() const = 0;
};
template <typename Type>
struct Sized : virtual SizedBase {
std::size_t size() const override {
return sizeof(Type);
}
};
struct Base : Sized<Base> {};
struct Derived : Base, Sized<Derived> {};
This looks much better, but sadly is ill-formed: Derived contains two final overriders for size() from Base and from Sized<Derived>. We can solve this by inheriting through Sized:
struct SizedBase {
virtual std::size_t size() const = 0;
};
template <typename Type, typename... SizedBases>
struct Sized : virtual SizedBase, SizedBases... {
std::size_t size() const override {
return sizeof(Type);
}
};
struct Base : Sized<Base> {};
struct Derived : Sized<Derived, Base> {};
This works as intended, however gets somewhat confusing in the event of multiple inheritance and prohibits altering accessibility/virtualness of bases.
So, is there a better way?
Not that anyone should really use this, but...
template <typename>
struct None1 {};
template <typename>
struct None2 {};
template <typename T>
struct PrivateBase { using Tpriv = T; using Tprot = None1<T>; using Tpub = None2<T>; };
template <typename T>
struct ProtectedBase { using Tpriv = None1<T>; using Tprot = T; using Tpub = None2<T>; };
template <typename T>
struct PublicBase { using Tpriv = None1<T>; using Tprot = None2<T>; using Tpub = T; };
template <typename K>
struct TriBase : private K::Tpriv, protected K::Tprot, public K::Tpub {};
template <typename T, typename ... Bases>
struct Sized : private Bases::Tpriv..., protected Bases::Tprot..., public Bases::Tpub...
{
virtual size_t size() { return sizeof(T); }
};
struct Foo : Sized<Foo> {};
struct X{};
struct Y{};
struct Bar : Sized<Bar, PrivateBase<X>, ProtectedBase<Y>, PublicBase<Foo>> {};
int main ()
{
Bar b;
Foo* f = &b;
X* x = &b; // error : private base
Y* y = &b; // error : protected base
}
Virtual inheritance is left as an exercise to the reader.
The order of base classes is not preserved, but you should not depend on it anyway.
Something that is a little bit more production-friendly can be implemented like this (this is a rough sketch):
#include <cstdlib>
#include <typeinfo>
#include <unordered_map>
#include <memory>
#include <iostream>
struct myinfo
{
size_t size;
// any other stuff
};
using TypeInfoRef = std::reference_wrapper<const std::type_info>;
struct Hasher
{
std::size_t operator()(TypeInfoRef code) const
{
return code.get().hash_code();
}
};
struct EqualTo
{
bool operator()(TypeInfoRef lhs, TypeInfoRef rhs) const
{
return lhs.get() == rhs.get();
}
};
static std::unordered_map<TypeInfoRef, myinfo, Hasher, EqualTo> typemap;
template <typename K>
struct typemap_initializer
{
typemap_initializer()
{
typemap[typeid(K)] = myinfo{sizeof(K)};
}
};
struct Base
{
virtual ~Base() {}
size_t size() { return typemap[typeid(*this)].size; }
template<typename K, typename... Arg>
friend K* alloc(Arg...);
private:
void* operator new(size_t sz) { return ::operator new(sz); }
};
template<typename K, typename... Arg>
K* alloc(Arg... arg)
{
static typemap_initializer<K> ti;
return new K(arg...);
}
struct Foo : Base {int a;};
struct Bar : Foo {int b; int c;};
int main ()
{
Foo* f = alloc<Foo>();
Bar* g = alloc<Bar>();
std::cout << f->size() << std::endl;
std::cout << g->size() << std::endl;
}
Of course one gives up the familiar Foo* foo = new Foo syntax, but in the era of ubiquitous std::make_shared<> this is not a big problem.
template <typename T, typename C>
class CSVWriter{
template <typename PrinterT>
void write(std::ostream& stream, const PrinterT& printer){
}
};
I want to check whether there exists at least two overloads PrinterT::operator()(T*) and PrinterT::operator()(C*)
PrinterT may or may not inherit from std::unary_function
What concept Checking Classes I need to use here ?
(I am not using C++11)
You can use something like that
#include <iostream>
#include <boost/concept/requires.hpp>
#include <boost/concept/usage.hpp>
template <class Type, class Param>
class has_operator_round_brackets_with_parameter
{
public:
BOOST_CONCEPT_USAGE(has_operator_round_brackets_with_parameter)
{
_t(_p);
}
private:
Type _t;
Param _p;
};
struct X {};
struct Y {};
struct Test1
{
void operator() (X*) const { }
};
struct Test2: public Test1
{
void operator() (X*) const { }
void operator() (Y*) const { }
};
template <class T, class C>
struct CSVWriter
{
template <class PrinterT>
BOOST_CONCEPT_REQUIRES(
((has_operator_round_brackets_with_parameter<PrinterT, T*>))
((has_operator_round_brackets_with_parameter<PrinterT, C*>)),
(void)) write(std::ostream& stream, const PrinterT& printer)
{
}
};
int main()
{
CSVWriter<X, Y> w;
// w.write<Test1>(std::cout, Test1()); // FAIL
w.write<Test2>(std::cout, Test2()); // OK
return 0;
}