How to implement a very simple edition of boost::bind, which does not bind arguments, but offer a way to call member function in c++ classes.
Here is my first try:
#include <iostream>
struct Foo {
void x(int i) { std::cout << "Foo " << i << std::endl; }
};
struct Bar {
void y(int i) { std::cout << "Bar " << i << std::endl; }
};
template<typename A1, typename I, typename M>
struct Binder {
Binder(I i, M m) : i_(i), m_(m) { }
void operator()(A1 a1) {
(i_->*m_)(a1);
}
I i_;
M m_;
};
template<typename A1, typename I, typename M>
Binder<A1, I, M> my_bind(I i, M m) {
return Binder<A1, I, M>(i, m);
}
int main(int argc, const char *argv[])
{
Foo foo;
Bar bar;
Binder<int, Foo*, void (Foo::*)(int)> b1 = my_bind<int>(&foo, &Foo::x);
Binder<int, Bar*, void (Bar::*)(int)> b2 = my_bind<int>(&bar, &Bar::y);
b1(1);
b2(2);
return 0;
}
The implementation above does work, and will print:
Foo 1
Bar 2
The problem is that the two invokes of my_bind returns objects of different types. How can I alter the program, such that my_bind will return a type which only depends on A1.
The problem is that the two invokes of my_bind returns objects of different types. How can I alter the program, such that my_bind will return a type which only depends on A1.
It is possible to do with type erasure.
In short:
Create Abstract class with interface you like to have. It may have some template parameters. (AbstractBinder in below code)
Create Concrete class which implements this interface. Concrete class may have more template arguments than interface. (Binder class below)
Create Holder class with template constructor - which creates Concrete class, but stores only pointer to it's base Abstract class. So, Holder class has only template parameters required for Abstract interface, while its constructor has all the rest template parameters required for Concrete class. (BinderHolder class below)
live demo
Usage:
int main()
{
Foo foo;
Bar bar;
BinderHolder<int> b1 = my_bind<int>(&foo, &Foo::x);
BinderHolder<int> b2 = my_bind<int>(&bar, &Bar::y);
b1(1);
b2(2);
}
Full code:
template<typename A1>
struct AbstractBinder
{
virtual void call(A1 a1)=0;
virtual AbstractBinder<A1> *clone()=0;
virtual ~AbstractBinder(){}
};
template<typename A1, typename I, typename M>
struct Binder : AbstractBinder<A1>
{
Binder(I i, M m) : i_(i), m_(m) { }
void call(A1 a1)
{
(i_->*m_)(a1);
}
virtual AbstractBinder<A1> *clone()
{
return new Binder(*this);
}
I i_;
M m_;
};
template<typename A1>
class BinderHolder
{
AbstractBinder<A1> *ptr;
BinderHolder &operator=(const BinderHolder&);
public:
template<typename I, typename M>
BinderHolder(I i, M m)
: ptr(new Binder<A1,I,M>(i,m))
{
}
BinderHolder(const BinderHolder &rhs)
: ptr(rhs.ptr->clone())
{
}
~BinderHolder()
{
delete ptr;
}
void operator()(A1 a1)
{
ptr->call(a1);
}
};
template<typename A1, typename I, typename M>
BinderHolder<A1> my_bind(I i, M m) {
return BinderHolder<A1>(i, m);
}
#include <iostream>
struct Foo {
void x(int i) { std::cout << "Foo " << i << std::endl; }
};
struct Bar {
void y(int i) { std::cout << "Bar " << i << std::endl; }
};
int main()
{
Foo foo;
Bar bar;
BinderHolder<int> b1 = my_bind<int>(&foo, &Foo::x);
BinderHolder<int> b2 = my_bind<int>(&bar, &Bar::y);
b1(1);
b2(2);
}
P.S. If you are sure, that all your Concrete classes would have same size, then you can replace heap allocations with placement new inside to fixed size buffer, and add static_assert for safety.
Related
I believe this is fairly simply to achieve, but I can't figure out how.
Take the following example class:
class Example {
public:
template <typename T>
size_t foo(T& v) const;
};
How can I provide two implementations for this method depending on if T is a POD? I know there is an std::is_pod type trait, but I can't figure out how to have it enable the correct function.
I also need to be able to provide specific specializations for certain types of T regardless of if they are PODs or not. For example, I want to be able to write:
template <>
size_t foo<uint8_t>(uint8_t& b);
While all other types of T are chosen based upon being PODs or not.
EDIT
I have been looking at the information everyone has been giving and have come up with the following, however, this still does not work (throws a compiler error). I can't understand why.
class Example {
public:
template <typename T, bool U = std::is_trivially_copyable<T>::value>
size_t foo(T& v) const;
};
template <typename T>
size_t Example::foo<T, true>(T& v) const {
//Do something if T is mem copyable
}
template <typename T>
size_t Example::foo<T, false>(T& v) const {
//Do something if T is not mem copyable
}
Which results in "non-class, non-variable partial specialization 'foo<T, true>' is not allowed"
You can do it in the following way.
#include <iostream>
#include <type_traits>
struct A {
int m;
};
struct B {
int m1;
private:
int m2;
};
struct C {
virtual void foo() {};
};
// is_pod is deprecated since C++ 20
template <typename T>
std::enable_if_t<std::is_pod_v<T>, size_t> foo(const T& pod)
{
std::cout << &pod << " is_pod\n";
return 0;
}
template <>
size_t foo<uint8_t>(const uint8_t& b)
{
std::cout << int(b) << " is uint8_t\n";
return 1;
}
template <>
size_t foo<int>(const int& b)
{
std::cout << int(b) << " is int\n";
return 1;
}
int main()
{
uint8_t a = 2;
foo(a);
foo(22);
// will compile
A instance;
foo(instance);
// will not compile
B b;
//foo(b);
// will not compile
C c;
//foo(c);
}
output
2 is uint8_t
22 is int
010FFA64 is_pod
Here is what I did to get it to work correctly:
#include <type_traits>
#include <iostream>
class Example {
public:
Example(int a) : _a(a) {}
virtual void bar() {}
template <typename T, typename std::enable_if<std::is_trivially_copyable<T>::value, size_t>::type = 0>
size_t foo(T& v) const {
std::cout << "T is trivially copyable" << std::endl;
return sizeof(T);
}
template <typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, size_t>::type = 0>
size_t foo(T& v) const {
std::cout << "T is not trivially copyable" << std::endl;
return sizeof(T);
}
private:
int _a;
int _b;
int _c;
};
template <>
size_t Example::foo<unsigned int>(unsigned int& v) const {
std::cout << "T is unsigned int" << std::endl;
return sizeof(unsigned int);
}
int main() {
Example e(10);
int a;
e.foo(a);
char b;
e.foo(b);
e.foo(e);
unsigned int c;
e.foo(c);
return 0;
}
The output of which looks like:
T is trivially copyable
T is trivially copyable
T is not trivially copyable
T is unsigned int
This is based upon the following Provide/enable method to in a class based on the template type
I instance a template and want to use that instance for other template
template <typename I> class A
{
I name;
public:
A(I n){
name = n;
}
void show() const
{
cout << name << "\t";
}
};
template <template<typename I> class V> class B {
V origen;
public:
B (V o){
origen = o;
}
};
auto main() -> int
{
cout << "[code.cpp]" << endl;
A<int> a1(1);
a1.show();
B<A> b1(a1);
return 0;
}
What I see about this topic is that´s not usually use, but when use, not used in this form, and I don't understand why.
I tried using const. Not working
V origen; and void B (V o) are invalid as V is not a type.
Maybe you want
template <typename T> class B;
template <template<typename> class V, typename T>
class B<V<T>>
{
V<T> origen;
public:
B (V<T> o) : origen(o) {}
};
and then
A<int> a1(1);
B<A<int>> b1(a1);
Or maybe
template <template<typename> class V>
class B
{
V<int> origen;
public:
B (V<int> o) : origen(o) {}
};
and then
A<int> a1(1);
B<A> b1(a1);
I have an object S. S is composed of layers S0, S1, S2 ... just like a stack of stackable drawers.
I want to create a chain of template classes A, B, C such that:
They represents proxies to different layers of the S object.
Even during template instantiation, C can convert to B, which can convert to A.
A, B, and C have different sets of methods.
The problem is that if I use public inheritance, then C will get the methods of A and B.
Test:
#include <iostream>
// Library
template <typename T>
class A {
public:
void a() {std::cout << "a\n"; }
int s_{0};
};
template <typename T>
class B : public A<T> {
public:
void b() {std::cout << "b\n"; }
};
template <typename T>
class C : public B<T> {
public:
void c() {std::cout << "c\n"; }
};
// User of library write a function like this
template <typename T>
void foo(A<T>& a) { a.a(); }
// The problem:
int main() {
C<int> c;
foo(c);
c.a(); // <--- how to hide this?
return 0;
}
I'm not sure if I understand what you want. But one way to do it is changing the access level of base class member in derived class. For example:
template <typename T>
class C : public B<T> {
public:
void c() { std::cout << "c\n"; }
private:
using A::a; // <-- reduce access level of base class member
};
"Just" need 0 + 1 + 2 + ... + i conversion operators for layer Si
Or one template conversion operator if their attributes are all the same.
But this still need some way to control the conversions.
#include <iostream>
template <typename T>
class A {
public:
A(int& layer) : layer_(layer) {}
void a() {std::cout << "a\n"; }
int s_{0};
private:
int& layer_;
};
template <typename T>
class B {
public:
B(int& layer) : a_(layer) { }
template <template<typename> class X, typename T2>
operator X<T2>() { return a_; }
void b() {std::cout << "b\n"; }
private:
A<T> a_;
};
template <typename T>
class C {
public:
C(int& layer) : b_(layer) {}
template <template<typename> class X, typename T2>
operator X<T2>() { return b_; }
void c() {std::cout << "c\n"; }
private:
B<T> b_;
};
template <typename T>
class D {
public:
D(int& layer) : c_(layer) {}
template <template<typename> class X, typename T2>
operator X<T2>() { return c_; }
void c() {std::cout << "c\n"; }
private:
C<T> c_;
};
template <template<typename> class X, typename T>
void foo(X<T>& a) {
A<T>(a).a();
}
int main() {
int v = 1;
D<int> d(v);
foo(d);
return 0;
}
Can I overload a template class function in a class that extends its specialization?
I have the following piece of code (I've tried to simplify it to the bare minimum):
#include <iostream>
using namespace std;
class X {
public:
unsigned test_x() {
return 1;
}
};
class Y {
public:
unsigned test_y() {
return 2;
}
};
template <typename T, typename U>
class A {
public:
unsigned foo(U i) {
cout << "A" << endl;
return i.test_x();
}
unsigned bar(T i) {
return foo(i);
}
};
class B : public A<Y, X> {
public:
unsigned foo(Y i) {
cout << "B" << endl;
return i.test_y();
}
};
int main() {
B b = B();
Y y = Y();
cout << "Hello: " << b.bar(y) << endl;
return 0;
}
However the compiler produces the following error:
hello.cc: In member function ‘unsigned int A<T, U>::bar(T) [with T = Y, U = X]’:
hello.cc:47: instantiated from here
hello.cc:30: error: no matching function for call to ‘A<Y, X>::foo(Y&)’
hello.cc:24: note: candidates are: unsigned int A<T, U>::foo(U) [with T = Y, U = X]
Basically I would like to overload the function A::foo() in its derived class B.
Apparently what you're asking is called "static polymorphism" and it's achieved by the means of "curiously recurring template pattern":
template <typename Derived, typename T, typename U>
class A {
public:
unsigned foo(U i) {
cout << "A" << endl;
return i.test_x();
}
unsigned bar(T i) {
return static_cast<Derived*>(this)->foo(i);
}
};
class B : public A<B, Y, X> {
public:
// Uncomment this line if you really want to overload foo
// instead of overriding. It's optional in this specific case.
//using A::foo;
unsigned foo(Y i) {
cout << "B" << endl;
return i.test_y();
}
};
I don't think the overloads in derived classes cannot be used from the base class where they are to be called from.
What you can do, is to extract the foo method, so you can specialize it for B.
#include <iostream>
using namespace std;
class X {
public:
unsigned test_x() {
return 1;
}
};
class Y {
public:
unsigned test_y() {
return 2;
}
};
template <typename T, typename U>
struct Foo
{
unsigned foo(U i) {
cout << "A" << endl;
return i.test_x();
}
};
template <typename T, typename U>
class A : public Foo<T, U> {
public:
unsigned bar(T i) {
return this->foo(i);
}
};
template <>
struct Foo<Y, X>
{
public:
unsigned foo(Y i) {
cout << "B" << endl;
return i.test_y();
}
};
class B : public A<Y, X> {
};
int main() {
B b = B();
Y y = Y();
cout << "Hello: " << b.bar(y) << endl;
return 0;
}
Edit: My first answer was incorrect.
When you instantiate A with classes Y and X the call of foo(T) generates an error because there no proper overloaded method defined in A. It suffices to declare a pure virtual method of foo(T) in A and implement this method in B.
template <typename T, typename U>
class A {
public:
virtual unsigned foo(T i) = 0;
unsigned foo(U i) { /* as above */ }
unsigned bar(T i) {
return foo(i); // calls abstract foo(T)
}
};
/* B is left untouched */
Compiling this generates this output:
B
Hello: 2
I have a templated class A<T, int> and two typedefs A<string, 20> and A<string, 30>.
How do I override the constructor for A<string, 20> ? The following does not work:
template <typename T, int M> class A;
typedef A<std::string, 20> one_type;
typedef A<std::string, 30> second_type;
template <typename T, int M>
class A {
public:
A(int m) {test= (m>M);}
bool test;
};
template<>
one_type::one_type() { cerr << "One type" << endl;}
I would like the class A<std::string,20> to do something that the other class doesn't. How can I do this without changing the constructor A:A(int) ?
The only thing you cannot do is use the typedef to define the constructor. Other than that, you ought to specialize the A<string,20> constructor like this:
template<> A<string,20>::A(int){}
If you want A<string,20> to have a different constructor than the generic A, you need to specialize the whole A<string,20> class:
template<> class A<string,20> {
public:
A(const string& takethistwentytimes) { cerr << "One Type" << std::endl; }
};
Assuming your really meant for A::test to be publicly accessible, you could do something like this:
#include <iostream>
template <int M>
struct ABase
{
ABase(int n) : test_( n > M )
{}
bool const test_;
};
template <typename T, int M>
struct A : ABase<M>
{
A(int n) : ABase<M>(n)
{}
};
template <typename T>
A<T, 20>::A(int n)
: ABase<20>(n)
{ std::cerr << "One type" << std::endl; }
Kick the tires:
int main(int argc, char* argv[])
{
A<int, 20> a(19);
std::cout << "a:" << a.test_ << std::endl;
A<int, 30> b(31);
std::cout << "b:" << b.test_ << std::endl;
return 0;
}
Late but a very elegant solution:
C++ 2020 introduced Constraints and Concepts. You can now conditionally enable and disable constructors and destructors!
#include <iostream>
#include <type_traits>
template<class T>
struct constructor_specialized
{
constructor_specialized() requires(std::is_same_v<T, int>)
{
std::cout << "Specialized Constructor\n";
};
constructor_specialized()
{
std::cout << "Generic Constructor\n";
};
};
int main()
{
constructor_specialized<int> int_constructor;
constructor_specialized<float> float_constructor;
};
Run the code here.
This may be a little bit late, but if you have access to c++11 you can use SFINAE to accomplish just what you want:
template <class = typename std::enable_if<
std::is_same<A<T,M>, A<std::string, 20>>::value>::type // Can be called only on A<std::string, 20>
>
A() {
// Default constructor
}
Working example
How about :
template<typename T, int M, bool dummy = (M > 20) >
class A {
public:
A(int m){
// this is true
}
};
template<typename T, int M>
class A<T,M,false> {
public:
A(int m) {
//something else
}
};
You can't with your current approach. one_type is an alias to a particular template specialization, so it gets whatever code the template has.
If you want to add code specific to one_type, you have to declare it as a subclass of A specialization, like this:
class one_type:
public A<std::string, 20>
{
one_type(int m)
: A<str::string, 20>(m)
{
cerr << "One type" << endl;
}
};
The best solution I've been able to come up with for this situation is to use a "constructor helper function":
template <typename T, int M> class A;
typedef A<std::string, 20> one_type;
typedef A<std::string, 30> second_type;
template <typename T, int M>
class A {
private:
void cons_helper(int m) {test= (m>M);}
public:
A(int m) { cons_helper(m); }
bool test;
};
template <>
void one_type::cons_helper(int) { cerr << "One type" << endl;}