polymorphic arguments in a function pointer in C++ - c++

Is it possible to safely cast between two function pointer in C++, given that the arguments as polymorphicly equivalent i.e. (example only)
class Base {}
class A : Base {}
class B : Base {}
class C : Base {}
template<typename T, typename U>
using FPTR = void (*)(const T&, const U&);
using index = std::pair<std:type_info, std::type_info>;
std::unordered_map<index, FPTR<Base, Base>> func_map;
template<typename T, typename U>
register(FPTR<T,U> fptr) {
// assert T and U are subclasses of Base
func_map[index(typeid(T), typeid(U))] = fptr;
}
void call(const Base& first, const Base& second) {
auto it = func_map.find(index(typeid(first), typeid(second)));
if (it != func_map.end()) {
(*it)(first, second)
}
}
void func1(const A&, const C&) {}
// call these
register<A,C>(func1);
register<B,B>([](const B&, const B&) -> void {});
so when invoking call, it would resolve the function to call based on the registered typeids, and the called function would expect the explicit type, effectively casting from the base type.
My thinking is this is going to cause an error at run time because the cast wron't occur correctly. I've considered using a lambda function to wrap fptr, but that would result in an extra indirect call, is there a way to avoid this while correctly performing the cast, note I can't cast in call, because I can only get the typeid/type_info and can't use that with the cast functions.

You can do it with an extra direct call, if that's not a problem (the target call might even be in-lineable in the wrapper, depending on your compiler and how the translation units are set up).
Something like:
struct Base {}
// ...
template <typename T, typename U>
using FPTR = void (*)(const T&, const U&);
template <typename T, typename U, FPTR<T,U> fptr>
void WrapFPTR(const Base &a, const Base &b)
{
fptr(static_cast<const T&>(a), static_cast<const U&>(b));
}
allows you to store WrapFPTR<T,U,foo> which is an FPTR<Base,Base> at every site where you register a given function foo.
If you really need an arbitrary function pointer, you'd need to store a polymorphic closure object with a pointer to that function's concrete type instead.

Current C++ contains no elaborate notion of co(ntra)variance. Can you go with static mapping instead?
#include <iostream>
class Base {};
class A : Base {};
class B : Base {};
class C : Base {};
template<typename T, typename U> using FPTR = void (*)(const T&, const U&);
// instead of allocating a run-time map, create a map on compiler's heap at compile-time
template<typename U, typename V> static FPTR<U const &, V const &> funcMap;
void nyan(A const &, A const &) { std::cout << "Nyan" << std::endl; }
void meow(B const &, B const &) { std::cout << "Meow" << std::endl; }
int main() {
funcMap<A, A> = nyan;
funcMap<B, B> = meow;
funcMap<A, A>(A{}, A{});
}

Related

Factory method combining static and dynamic polymorphism

I am working with two corresponding class hierarchies, A and B, where I need to create instances of sub-types of B from instances of matching sub-types of A. I can't find a "clean" way to create B objects from A objects because
B objects only have pointers to A objects so a B::factory would not know what kind of B to make as it doesn't know what derived type of A it gets without some sort of ugly dynamic_cast that would be hard to maintain as new sub-types of A and B are added to the library.
B classes depend on template parameters that A classes do not. It's not obvious how a factory method in A could therefore create a B since A classes have virtual inheritance and such a method would need to be templated, which is not possible.
Example classes:
template<typename T>
struct AType {
virtual void apply( const T*, T* ) const = 0;
};
template<typename T>
struct ASubType1 : public AType<T> {
void apply( const T*, T* ) const override;
};
template<typename T>
struct ASubType2 : public AType<T> {
void apply( const T*, T* ) const override;
};
template<typename T, typename U>
class BType {
public:
BType( const AType<T>* A_in ) : A(A_in) {}
virtual std::common_type_t<T,U> compute( const U& ) = 0;
static std::unique<BType> factory( const AType<T>* A_in );
// if A_in has type ASubType1, return std::make_unique<BSubType1<T,U>>
// else if A_in has type ASubType2, return std::make_unique<BSubType2<T,U>>
// else return nullptr
protected:
auto get_A() const { return A; } // So BSubTypes have access
private:
AType<T>* A;
};
template<typename T, typename U>
class BSubType1 : public BType<T,U> {
public:
using BType<T,U>::BType;
std::common_type_t<T,U> compute( const U& ) override;
};
template<typename T, typename U>
class BSubType2 : public BType<T,U> {
public:
using BType<T,U>::BType;
std::common_type_t<T,U> compute( const U& ) override;
};
It seems like there ought to be some sort of clever Vistor-based solution to generating the correct B objects from their corresponding A, however, the only solution besides dynamic_cast
that I have found is to add a method to the A classes that can return an enum corresponding to each A sub-type and have B::factory take this enum as an argument to return the correct sub-type of B. This approach is not particularly satisfying as it requires intrusively changing type information in a base class, where it would be desirable to add new classes to the A and B families without having to touch any existing classes.
Is there a more elegant approach, such as one using visitors, than what I am currently doing?

Property system based on std::any: template type deduction

To implement a property system for polymorphic objects, I first declared the following structure:
enum class access_rights_t
{
NONE = 0,
READ = 1 << 0,
WRITE = 1 << 1,
READ_WRITE = READ | WRITE
};
struct property_format
{
type_index type;
string name;
access_rights_t access_rights;
};
So a property is defined with a type, a name and access rights (read-only, write-only or read-write). Then I started the property class as follows:
template<typename Base>
class property : property_format
{
public:
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
template<typename Derived, typename T>
using set_t = function<void(Derived&, const T&)>;
private:
get_t<Base, any> get_f;
set_t<Base, any> set_f;
The property is associated to a base type, but may (and will) be filled with accessors associated to an instance of a derived type. The accessors will be encapsulated with functions accessing std::any objects on an instance of type Base. The get and set methods are declared as follows (type checking are not shown here to make the code minimal):
public:
template<typename T>
T get(const Base& b) const
{
return any_cast<T>(this->get_f(b));
}
template<typename T>
void set(Base& b, const T& value_)
{
this->set_f(b, any(value_));
}
Then the constructors (access rights are set to NONE to make the code minimal):
template<typename Derived, typename T>
property(
const string& name_,
get_t<Derived, T> get_,
set_t<Derived, T> set_ = nullptr
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
set_f{caller<Derived, T>{set_}}
{
}
template<typename Derived, typename T>
property(
const string& name_,
set_t<Derived, T> set_
):
property{
name_,
nullptr,
set_
}
{
}
The functions passed as arguments are encapsulated through the helper structure caller:
private:
template<typename Derived, typename T>
struct caller
{
get_t<Derived, T> get_f;
set_t<Derived, T> set_f;
caller(get_t<Derived, T> get_):
get_f{get_}
{
}
caller(set_t<Derived, T> set_):
set_f{set_}
{
}
any operator()(const Base& object_)
{
return any{
this->get_f(
static_cast<const Derived&>(object_)
)
};
}
void operator()(Base& object_, const any& value_)
{
this->set_f(
static_cast<Derived&>(object_),
any_cast<Value>(value_)
);
}
};
Now, considering these dummy classes.
struct foo
{
};
struct bar : foo
{
int i, j;
bar(int i_, int j_):
i{i_},
j{j_}
{
}
int get_i() const {return i;}
void set_i(const int& i_) { this->i = i_; }
};
I can write the following code:
int main()
{
// declare accessors through bar methods
property<foo>::get_t<bar, int> get_i = &bar::get_i;
property<foo>::set_t<bar, int> set_i = &bar::set_i;
// declare a read-write property
property<foo> p_i{"bar_i", get_i, set_i};
// declare a getter through a lambda
property<foo>::get_t<bar, int> get_j = [](const bar& b_){ return b_.j; };
// declare a read-only property
property<foo> p_j{"bar_j", get_j};
// dummy usage
bar b{42, 24};
foo& f = b;
cout << p_i.get<int>(f) << " " << p_j.get<int>(f) << endl;
p_i.set<int>(f, 43);
cout << p_i.get<int>(f) << endl;
}
My problem is that template type deduction doesn't allow me to declare a property directly passing the accessors as arguments, as in:
property<foo> p_i{"bar_i", &bar::get_i, &bar::set_i};
Which produces the following error:
prog.cc:62:5: note: template argument deduction/substitution failed:
prog.cc:149:50: note: mismatched types std::function<void(Type&, const Value&)> and int (bar::*)() const
property<foo> p_i{"bar_i", &bar::get_i, set_i};
Is there a way to address this problem while keeping the code "simple"?
A complete live example is available here.
std::function is a type erasure type. Type erasure types are not suitable for deduction.
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
get_t is an alias to a type erasure type. Ditto.
Create traits classes:
template<class T>
struct gettor_traits : std::false_type {};
this will tell you if T is a valid gettor, and if so what its input and output types are. Similarly for settor_traits.
So
template<class T, class Derived>
struct gettor_traits< std::function<T(Derived const&)> >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
template<class T, class Derived>
struct gettor_traits< T(Derived::*)() >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
etc.
Now we got back to the property ctor:
template<class Gettor,
std::enable_if_t< gettor_traits<Gettor>{}, int> =0,
class T = typename gettor_traits<Gettor>::return_value,
class Derived = typename gettor_traits<Gettor>::argument_type
>
property(
const string& name_,
Gettor get_
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
nullptr
{
}
where we use SFINAE to ensure that our Gettor passes muster, and the traits class to extract the types we care about.
There is going to be lots of work here. But it is write-once work.
My preferred syntax in these cases would be:
std::cout << (f->*p_i)();
and
(f->*p_i)(7);
where the property acts like a member function pointer, or even
(f->*p_i) = 7;
std::cout << (f->*p_i);
where the property transparently acts like a member variable pointer.
In both cases, through overload of ->*, and in the second case via returning a pseudo-reference from ->*.
At the end of this answer is a slightly different approach. I will begin with the general problem though.
The problem is &bar::get_i is a function pointer to a member function while your alias is creating a function object which needs the class as additional template parameter.
Some examples:
Non member function:
#include <functional>
void a(int i) {};
void f(std::function<void(int)> func)
{
}
int main()
{
f(&a);
return 0;
}
This works fine. Now if I change a into a struct:
#include <functional>
struct A
{
void a(int i) {};
};
void f(std::function<void(int)> func)
{
}
int main()
{
f(std::function<void(int)>(&A::a));
return 0;
}
this gets the error:
error: no matching function for call to std::function<void(int)>::function(void (A::*)(int))'
because the std::function object also need the base class (as you do with your alias declaration)
You need a std::function<void(A,int)>
You cannot make your example much better though.
A way to make it a "bit" more easier than your example would maybe be this approach using CRTP.
#include <functional>
template <typename Class>
struct funcPtr
{
template <typename type>
using fun = std::function<void(Class,type)>;
};
struct A : public funcPtr<A>
{
void a(int i) {};
};
void f(A::fun<int> func)
{
};
int main()
{
f(A::fun<int>(&A::a));
return 0;
}
And each your "derived" classes derives from a funcPtr class which "auto generates" the specific alias declaration.

getting key_type from value_type

I have a class X that operates on std containers. A function that takes a value_type as argument must call a function that takes a key_type as argument. How do I do that? I seems so basic.
template<typename C>
class X
{
void foo(typename C::value_type vt)
{
bar(vt.first); // this works for C = std::map
bar(vt); // this works for C = std::set
}
void bar(typename C::key_type kt)
{
...
}
};
Add a (private) bar overload that is a function template and takes a T::value_type as argument.
template<typename C>
class X
{
public:
void foo(typename C::value_type vt)
{
bar(vt);
}
void bar(typename C::key_type kt)
{}
private:
template<typename T = C>
void bar(typename T::value_type kt)
{
bar(kt.first);
}
};
When C is an std::map, the call to bar within foo will resolve to the member function template, and it'll then call other bar with the correct argument.
When C is an std::set, the call to bar will match both the bar overloads, but since one is a member function template, and the other isn't, the latter will be considered a better match.
Live demo

Run different code for a class that has either an object or an array of objects as a member

I have a method that takes an object as parameter
void fun(const Obj& obj)
Obj can be defined in two different ways:
struct Obj
{
Type x;
};
and
struct Obj
{
Type x[42];
};
I cannot modify the definitions of Obj (i.e. I can't rename the classes). Also, I can't modify the signature of fun and I'd rather not use preprocessor directives inside of fun. Is there a way to use metaprogramming to make this compile and work regardless of which definition of Obj is included:
void fun(const Obj& obj)
{
impl(obj); // executes some code if obj.x is an object
// executes some other code if obj.x is an array
}
? Is there a way to do it without C++11 features?
You could pick a specialization of a template based on decltype(obj.x):
template<typename T>
void impl(const Obj&);
template<>
void impl<Type>(const Obj&) {}
template<>
void imp<Type[42]>(const Obj&) {}
void fun(const Obj& obj)
{
impl<decltype(obj.x)>(obj);
}
Possible C++03 way is a member detector trait class that checks for existence of Type Obj::x. This time, template parameter of impl would be bool so you can simply pass the result of the check:
template<typename C>
struct has_Type_x {
template<typename U, U>
struct Check;
typedef char(&yes)[1];
typedef char(&no)[2];
template<typename> static no test(...);
template<typename U> static yes test(Check<Type U::*, &U::x>*);
static const bool value = sizeof(test<C>(0)) == sizeof(yes);
};
template<bool> void impl(const Obj&);
template<>
void impl<true>(const Obj&) {}
template<>
void impl<false>(const Obj&) {
std::cout << "arr";
}
void fun(const Obj& obj)
{
impl< has_int_x<Obj>::value >(obj);
}
This can be done by a second call to an implementation function fun_impl that also takes obj.x as an argument. This function specializes to scalars or arrays by two overloads, the latter accepting a reference to an array, so maintaining the array size as well:
template <typename Obj, typename T>
void fun_impl(const Obj& obj, const T& x) {}
template <typename Obj, typename T, size_t N>
void fun_impl(const Obj& obj, const T (&x)[N]) {}
template <typename Obj>
void fun(const Obj& obj)
{
fun_impl(obj, obj.x);
}
This works in C++03 and does not require any traits features or SFINAE. See also live example, where the remaining parts use C++11 for convenience.
If obj only contains x, you can drop it as an argument from fun_impl. I left it here for the more general case where obj might have other members as well.
Note that fun itself is given as a template here; I guess this is what you need to do anyway since you are dealing with different definitions of Obj.
My suggestion is to use function overloading. You don't need metaprogramming/templates in your case:
void fun(const Obj& obj)
{
impl(obj.x);
}
void impl(const Type& x){...}
void impl(Type x[]){...}
If Obj::x is declared as Type x then the first impl() version will be called. And similarly in another case the second impl() version will be called.

template typename question

I have a problem with template and wondering is there a possible way to achieve what I wanted to do. Here is my question.
template <typename T>
class A
{
public:
typedef T* pointer;
typedef const pointer const_pointer;
A()
{}
template <typename D>
A(const D& d)
{
// how can I store the D type
// so I can refer it later on
// outside of this function
}
};
ok here is a more complete code of what I wanted to do (it might not be compilable)
class C
{
public:
virtual ~C(){}
virtual void* get_d() = 0;
private:
};
template <typename T, typename D>
class Cimpl : public C
{
public:
Cimpl()
:t()
,d()
{}
Cimpl(const T& t, const D& d)
:t(t)
,(d)
{}
void* get_d()
{
return &reinterpret_cast<D&>(d);
}
private:
T t;
D d;
};
class B
{
public:
B()
:p(0)
{}
template <typename T, typename D>
B(const T& t, const D& d)
:p(0)
{
try
{
p = new Cimpl<T, D>(t, d);
}
catch(...)
{
d(p);
}
}
void* get_d()
{
return (p != 0) ? p->get_d() : 0;
}
~B()
{
delete p;
}
private:
C* p;
};
template <typename T>
class A
{
struct example_d
{
};
public:
typedef T* pointer;
typedef const pointer const_pointer;
A()
{}
template <typename D>
A(const T& t)
:b(t, example_d())
{
}
template <typename D>
A(const T& t, const D& d)
:b(t, d)
{
// how can I store the D type
// so I can refer it later on
// outside of this function
}
// not type safe...as user can cast to any type
// if I can store the type user pass in previous
// then I can use it back
template <typename T>
T* get_d()
{
reinterpret_cast<T*>(b.get_d());
}
private:
B b;
};
So I can use the class like
1)A<int> a(1);// with example_d as D
2)A<int> b(1, another_d()) // with another_d
I can change the template to take 2 parameters and use default parameter for 2nd type to be example_d. So I can achieve 1) but not 2). As I will have to code this way
A<int, another_d> b(1, another_d());
a bit too long to type...
You cannot store a type, you can only store objects.
(If you want to store the parameter d passed to A's constructor, look at type erasure.)
You can't "save" a typename like that. What you really want to do is make type D one of the template parameters of the class, e.g.
template <typename T, typename D>
class A
{
public:
typedef T* pointer;
typedef const pointer const_pointer;
A()
{}
A(const D& d)
{
}
};
Now, if your problem is that you want A<T> constructed with type D to be polymorphic with A<T> constructed with type E instead of having A<T,D> and A<T,E> be two different types, then the solution is a base class:
template <typename T>
class ABase
{
public:
typedef T* pointer;
typedef const pointer const_pointer;
ABase()
{}
protected:
/* You might want to omit this constructor completely,
* depending on your use case */
template<typename D>
ABase(const D& d)
{
}
};
template <typename T, typename D>
class A : public ABase<T>
{
public:
A()
{}
A(const D& d)
: ABase(d)
{
}
};
This looks like you are trying to create a template class that has a boost::any member variable. You should look at this a possible way of doing this.
Basically a boost::any can accept any value type. You can then retrieve that type safely if you know the type later. A good example of how you would use this is to store different datatypes in a map, (where you know the type later when you retrieve the the any by its name).
If this is not exactly what you are looking for the internals use a neat trick to implement it, and it will probably help you achieve what you are trying to do.
If you want to use type D in other member functions of class A, you can make D a second template parameter of class A.