I want to override virtual methods from base class with template methods in derived class; Just want to know if there is any smart way or work around to make this possible.
#include <iostream>
using namespace std;
struct A
{
virtual void AF(int i)
{
std::cout << "Function in A" << std::endl;
}
virtual void af(int i)
{
std::cout << "Function in A" << std::endl;
}
};
struct B
{
virtual void BF(int i)
{
std::cout << "Function in B" << std::endl;
}
virtual void bf(int i)
{
std::cout << "Function in B" << std::endl;
}
};
template<bool IS_A>
struct C : public A, public B
{
template<class I>
typename std::enable_if<std::is_same<int, I>::value && IS_A,void>::type AF(I i)
{
std::cout << "Function override from A in C" << std::endl;
}
template<class I>
typename std::enable_if<std::is_same<int, I>::value && !IS_A,void>::type BF(I i)
{
std::cout << "Function override from B in C" << std::endl;
}
template<class I>
void af(I i)
{
std::cout << "Function override from A in C" << std::endl;
}
template<class I>
void bf(I i)
{
std::cout << "Function override from B in C" << std::endl;
}
};
int main() {
int i(0);
{
A * a = new C<true>();
a->AF(i);
a->af(i);
}
{
B * b = new C<false>();
b->BF(i);
b->bf(i);
}
return 0;
}
Output is:
Function in A //Want this to be Function override from A in C
Function in A //Want this to be Function override from A in C
Function in B //Want this to be Function override from B in C
Function in B //Want this to be Function override from B in C
Thanks.
First, to "enable/disable" member functions according to IS_A, you can just define both true and false specializations of C:
template <bool IS_A>
struct C;
template <>
struct C<true> : A, B
{
// functions only defined for IS_A == true
};
template <>
struct C<false> : A, B
{
// functions only defined for IS_A == false
}
And to introduce the overriding by the template's, you can override the ones from A and B where you call the template ones:
void af(int i) override { af<int>(i); }
void bf(int i) override { bf<int>(i); }
You can use the CRTP idiom to do that:
#include <iostream>
#include<type_traits>
struct A
{
virtual void AF(int)
{
std::cout << "Function in A" << std::endl;
}
virtual void af(int)
{
std::cout << "Function in A" << std::endl;
}
};
struct B
{
virtual void BF(int)
{
std::cout << "Function in B" << std::endl;
}
virtual void bf(int)
{
std::cout << "Function in B" << std::endl;
}
};
template<typename D>
struct CRTP: public A, public B
{
template<typename I> void CAF(I i) { A::AF(i); }
template<typename I> void af(I i) { A::af(i); }
template<typename I> void CBF(I i) { B::BF(i); }
template<typename I> void cbf(I i) { B::bf(i); }
void AF(int i) override { static_cast<D*>(this)->CAF(i); }
void af(int i) override { static_cast<D*>(this)->caf(i); }
void BF(int i) override { static_cast<D*>(this)->CBF(i); }
void bf(int i) override { static_cast<D*>(this)->cbf(i); }
};
template<bool IS_A>
struct C : CRTP<C<IS_A>>
{
template<class I>
void CAF(I i)
{
std::cout << "Function override from A in C" << std::endl;
}
template<class I>
void CBF(I i)
{
std::cout << "Function override from B in C" << std::endl;
}
template<class I>
void caf(I i)
{
std::cout << "Function override from A in C" << std::endl;
}
template<class I>
void cbf(I i)
{
std::cout << "Function override from B in C" << std::endl;
}
};
int main()
{
int i(0);
{
A * a = new C<true>();
a->AF(i);
a->af(i);
}
{
B * b = new C<false>();
b->BF(i);
b->bf(i);
}
return 0;
}
Related
I'm writing a test program about c++ type erasure, the code is put on the end.
when I run program , the test case 2 output as follow:
A default cstr...0x7ffe0fe5158f
obj_:0x7ffe0fe5158f objaaa 0x7ffe0fe5158f
Print A 0x7ffe0fe5158f
my machine: Linux x86-64, gcc 4.8
In my opinion, "Object obj2(a2);" makes a class Model by lvalue reference, so it should call A's copy constructor,
but actually it did not work, it makes me confused.
someone can give a explanation, thank you in advance.
the program is list as follow:
#include <memory>
#include <iostream>
class Object {
public:
template <typename T>
Object(T&& obj) : object_(std::make_shared<Model<T>>(std::forward<T>(obj))) {
}
void PrintName() {
object_->PrintName();
}
private:
class Concept {
public:
virtual void PrintName() = 0;
};
template <typename T>
class Model : public Concept {
public:
Model(T&& obj) : obj_(std::forward<T>(obj)) {
std::cout << "obj_:" << std::addressof(obj_) <<" objaaa " << std::addressof(obj) << std::endl;
}
void PrintName() {
obj_.PrintName();
}
private:
T obj_;
};
private:
std::shared_ptr<Concept> object_;
};
class A {
public:
A(A& a) {
std::cout<< "A copy cstr...a" << this << std::endl;
}
A(A&& a) {
std::cout << "A move cstr...." <<this<< std::endl;
}
A() {
std::cout << "A default cstr..." <<this<< std::endl;
}
void PrintName() {
std::cout << "Print A " << this << std::endl;
}
};
int main(void)
{
// test case 1
Object obj{A()};
obj.PrintName();
// test case 2
A a2;
Object obj2(a2);
obj2.PrintName();
return 0;
}
In Object obj2(a2);, no copy is made. T in the constructor of Object is deduced to be A&, so it instantiates Model<A&>, which stores a reference to the original a2 object as its obj_ member.
Observe that in your debug output, a2's constructor, Model's constructor and PrintName all print the same address. You can further confirm that this address is in fact &a2.
struct Base
{
Base(int a_) : a(a_)
{
}
int a;
};
class Derived: public Base
{
public:
Derived(int i): Base(i)
{
}
Derived(const Derived && rhs)
: Base(std::move(rhs))
{
}
};
int main()
{
Derived d1(2);
Derived d2 = std::move(d1);
std::cout << d1.a << '\n';
}
Why the thing from which we just moved, that is, the thing that we just pilfered, is still accessible on subsequent lines of code? I mean d1.a.
Please tell me why move assignment is called in the following code.
In expression return Foo(static_cast<int>(value));, static_cast<int>(value) is rvalue, so move assignment is called. However, in expression return Foo(value);, value is an lvalue. Why move assignment is called instead of Foo(int val);
#include <bits/stdc++.h>
using namespace std;
class Foo {
public:
Foo() {}
Foo(int val)
{
value = val;
}
Foo(Foo& foo)
{
value = foo.value;
cout << "call Foo(Foo& foo)" << endl;
}
Foo(Foo&& foo)
{
value = foo.value;
foo.value = 0;
cout << "call Foo(Foo &&foo)" << endl;
}
Foo& operator=(Foo &foo)
{
value = foo.value;
cout << "call operator=(Foo& foo)" << endl;
return *this;
}
Foo& operator=(Foo &&foo)
{
value = foo.value;
foo.value = 0;
cout << "call operator=(Foo&& foo)" << endl;
return *this;
}
private:
int value;
};
Foo operator"" fo(unsigned long long value)
{
if (value < INT_MAX) {
// return Foo(static_cast<int>(value)); // call operator=(Foo&& foo)
return Foo(value); // call operator=(Foo&& foo)
} else {
throw "Over Range";
}
}
int main()
{
Foo foo;
foo = 123fo;
return 0;
}
I want to pass two functions with different signature into a same slot of class template parameter (one each time).
Ignore the strict syntax, this is what I want :-
void hf1 (int a) { std::cout<< "hf1" <<std::endl; }
void hf2 (int a, int i){ std::cout<< "hf2 "<<i<<std::endl; }
template<hfX> class Collection{
int i_=56;
public: test(){
if( "hfX has 1 param" ){hfX(0);} //call hf1
else {hfX(0,i_);} //call hf2
}
};
int main(){
Collection<&hf1> test1; test1.test(); // print "hf1"
Collection<&hf2> test2; test2.test(); // print "hf2 56"
}
Here is the code that works OK, but its usage is not so convenient :-
template<typename ... AA> using hfX = void(*)(AA ... );
void hf1 (int a) { std::cout<< "hf1" <<std::endl; }
void hf2 (int a, int i) { std::cout<< "hf2 "<<i <<std::endl; }
template <typename Tf, Tf F>
class Collection;
template <typename ... I, hfX<I...> F>
class Collection<hfX<I...>, F>{
public:
int i_=56;
template <std::size_t N = sizeof...(I)>
typename std::enable_if<N == 1U, void>::type test (){
F(0);
}
template <std::size_t N = sizeof...(I)>
typename std::enable_if<N == 2U, void>::type test (){
F(0,i_);
}
};
The usage:-
int main () {
Collection<hfX<int>, hf1> test1; //<--- #A dirty signature
Collection<hfX<int,int>, hf2> test2; //<--- #B dirty signature
test1.test(); // print "hf1"
test2.test(); // print "hf2 56"
}
Live version : https://ideone.com/f20BEk
Question
It would be nice if I can call it without explicit redundant signature.
Collection<hf1> test1; //or &hf
Collection<hf2> test2;
How to improve code (especially around hfX and Collection) to make its usage easier?
I don't know how to make what do you want with functions.
But if you can, instead of functions, accept to use static method in classes or structs (and pass that classes/structs as template argument)...
#include <iostream>
struct sf1
{ static void hf (int a) { std::cout << "hf1" << std::endl; } };
struct sf2
{ static void hf (int a, int i) { std::cout << "hf2 " << i << std::endl; } };
template <typename S>
class Collection
{
private:
int i_ = 56;
public:
template <typename T = S>
decltype(T::hf(0)) test() { S::hf(0); /*call sf1::hf */ }
template <typename T = S>
decltype(T::hf(0, 0)) test() { S::hf(0,i_); /*call sf2::hf */ }
};
int main ()
{
Collection<sf1> test1; test1.test(); // print "hf1"
Collection<sf2> test2; test2.test(); // print "hf2 56"
}
I have dug around quite a bit today and have come up empty. Is there any way to store a functor that is returned from a boost::bind with different types? I found an example that used boost::variants but not sure that this is needed. (Foo and Bar have been simplified for simplicity sake)
#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <map>
#include <iostream>
template <typename FooType>
struct Foo {
const FooType tmp_value;
Foo(const FooType& tmp_) :
tmp_value(tmp_)
{
}
template<typename Object>
void operator()(Object& operand)
{
std::cout << operand << std::endl;
operand += tmp_value;
}
};
template <typename BarType>
struct Bar {
const BarType tmp_value;
Bar(const BarType& tmp_) :
tmp_value(tmp_)
{
}
template<typename Object>
void operator()(Object& operand)
{
std::cout << operand << std::endl;
operand -= tmp_value;
}
};
typedef boost::variant<
boost::function<void(int32_t)>,
boost::function<void(int64_t)>,
boost::function<void(double)>,
boost::function<void(float)>
> my_functions;
typedef std::map<std::string, my_functions> test_map;
enum test_t {
FOO,
BAR
};
test_map createFunMap() {
test_map result;
for(int i = 0; i < 2; i++) {
switch(i) {
case test_t::FOO: {
std::cout << "In FOO" << std::endl;
Foo<double> p(1.0);
result.insert(std::pair<std::string,
boost::function<void(double)>>
("foo", boost::bind<void>(p, _1)));
break;
}
case test_t::BAR: {
std::cout << "In BAR" << std::endl;
Bar<int32_t> p(1.0);
result.insert(std::pair<std::string,
boost::function<void(int32_t)>>
("bar", boost::bind<void>(p, _1)));
break;
}
default:
std::cout << "just a default" << std::endl;
break;
}
}
return result;
}
int main() {
test_map myMap;
double t = 5.0;
myMap = createFunMap();
std::cout << t << std::endl;
myMap["foo"](t);
std::cout << t << std::endl;
return 0;
}
compiler output:
g++ -Wall --std=c++0x -I. test_ptrs.cc -o test_ptrs
test_ptrs.cc:93:2: error: type 'mapped_type' (aka 'boost::variant<boost::function<void (int)>, boost::function<void (long long)>, boost::function<void (double)>, boost::function<void (float)>,
boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>') does not provide a call operator
myMap["foo"](t);
^~~~~~~~~~~~
1 error generated.
Thanks.
You have polymorphic functors (Foo and Bar).
You want to type erase them for a certain set of operand types. I suggest defining a type-erased functor type for the purpose:
struct ErasedFunctor
{
template<typename F> ErasedFunctor(F&& f)
: pimpl(new impl_<F>(std::forward<F>(f))) {}
template <typename T>
void operator()(T& oper) const {
assert(pimpl);
pimpl->call(oper);
}
private:
typedef boost::variant<int32_t&, int64_t&, double&, float&> Operand;
struct base_ { virtual void call(Operand oper) const = 0; };
// struct impl_ : base_ ...
std::shared_ptr<base_> pimpl;
};
Now you can simply store the function objects directly in the map:
typedef std::map<std::string, ErasedFunctor> test_map;
test_map createFunMap() {
return test_map {
{ "foo", Foo<double>(1.0) },
{ "bar", Bar<int32_t>(1) },
};
}
Let's use at("foo") instead of ["foo"] to avoid having to make ErasedFunctor default-constructible:
int main() {
test_map myMap = createFunMap();
double t = 5.0;
std::cout << t << std::endl;
myMap.at("foo")(t);
std::cout << t << std::endl;
myMap.at("bar")(t);
std::cout << t << std::endl;
}
Prints
5
void ErasedFunctor::apply::operator()(const F&, T&) const [with F = Foo<double>; T = double](5)
5
6
void ErasedFunctor::apply::operator()(const F&, T&) const [with F = Bar<int>; T = double](6)
6
5
See it Live On Coliru
For more background see:
Generating an interface without virtual functions?
Full Sample
#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <iostream>
template <typename FooType> struct Foo {
const FooType tmp_value;
Foo(const FooType &tmp_) : tmp_value(tmp_) {}
template <typename Object> void operator()(Object &operand) const {
std::cout << operand << std::endl;
operand += tmp_value;
}
};
template <typename BarType> struct Bar {
const BarType tmp_value;
Bar(const BarType &tmp_) : tmp_value(tmp_) {}
template <typename Object> void operator()(Object &operand) const {
std::cout << operand << std::endl;
operand -= tmp_value;
}
};
struct ErasedFunctor
{
template<typename F> ErasedFunctor(F&& f)
: pimpl(new impl_<F>(std::forward<F>(f))) {}
template <typename T>
void operator()(T& oper) const {
assert(pimpl);
pimpl->call(oper);
}
private:
typedef boost::variant<int32_t&, int64_t&, double&, float&> Operand;
struct base_ { virtual void call(Operand oper) const = 0; };
struct apply : boost::static_visitor<void> {
template <typename F, typename T> void operator()(F const& f, T& v) const {
std::cout << __PRETTY_FUNCTION__ << "(" << v << ")\n";
f(v);
}
};
template <typename F> struct impl_ : base_ {
F f_;
impl_(F&& f) : f_(std::forward<F>(f)) { }
virtual void call(Operand oper) const override {
boost::apply_visitor(boost::bind(apply(), boost::cref(f_), _1), oper);
}
};
std::shared_ptr<base_> pimpl;
};
#include <map>
typedef std::map<std::string, ErasedFunctor> test_map;
test_map createFunMap() {
return test_map {
{ "foo", Foo<double>(1.0) },
{ "bar", Bar<int32_t>(1) },
};
}
int main() {
test_map myMap = createFunMap();
double t = 5.0;
std::cout << t << std::endl;
myMap.at("foo")(t);
std::cout << t << std::endl;
myMap.at("bar")(t);
std::cout << t << std::endl;
}