Consider the following standard CRTP example:
#include <iostream>
template<class Derived>
struct Base {
void f() { static_cast<Derived *>(this)->f(); }
void g() { static_cast<Derived *>(this)->g(); }
};
struct Foo : public Base<Foo> {
void f() { std::cout << 42 << std::endl; }
};
int main() {
Foo foo;
foo.f(); // just OK
foo.g(); // this will stack overflow and segfault
}
If this was regular virtual inheritance I could have mark virtual f and g methods as pure like
struct Base {
virtual void f() = 0;
virtual void g() = 0;
};
and get a compile time error about Foo being abstract. But CRTP offers no such protection. Can I implement it somehow? Runtime check is acceptable too. I thought about comparing this->f pointer with static_cast<Derived *>(this)->f, but didn't manage to make it work.
You can assert at compile time that the two pointers to member functions are different, e.g.:
template<class Derived>
struct Base {
void g() {
static_assert(&Derived::g != &Base<Derived>::g,
"Derived classes must implement g().");
static_cast<Derived *>(this)->g();
}
};
Here is another possibility:
#include <iostream>
template<class Derived>
struct Base {
auto f() { return static_cast<Derived *>(this)->f(); }
auto g() { return static_cast<Derived *>(this)->g(); }
};
struct Foo : public Base<Foo> {
void f() { std::cout << 42 << std::endl; }
};
int main() {
Foo foo;
foo.f(); // just OK
foo.g(); // this will not compile
}
For GCC, it gives a pretty clear error message ("error: use of 'auto Base::g() [with Derived = Foo]' before deduction of 'auto'"), while for Clang, it gives a slightly less readable infinitely recursing template instantiation of Base<Foo>::g, with g instantiating itself but eventually ending in an error.
You could use this solution, you can have pure "non-virtual abstract" function, and it maps as much as possible to CRTP this recommendation of H. Sutter:
template<class Derived>
struct Base
{
void f(){static_cast<Derived*>(this)->do_f();}
void g(){static_cast<Derived*>(this)->do_g();}
private:
//Derived must implement do_f
void do_f()=delete;
//do_g as a default implementation
void do_g(){}
};
struct derived
:Base<derived>
{
friend struct Base<derived>;
private:
void do_f(){}
};
You could consider doing something like this instead. You can make Derived a member and either supply it as a template parameter directly each time you instantiate a Base or else use a type alias as I have done in this example:
template<class Derived>
struct Base {
void f() { d.f(); }
void g() { d.g(); }
private:
Derived d;
};
struct FooImpl {
void f() { std::cout << 42 << std::endl; }
};
using Foo = Base<FooImpl>;
int main() {
Foo foo;
foo.f(); // OK
foo.g(); // compile time error
}
Of course Derived is no longer derived so you might pick a better name for it.
Related
I have class A that needs to invoke the member functions of template class B. Searching around I found this sample code on this site:
#include <iostream>
template<typename T, typename FType>
void bar(T& d, FType f) {
(d.*f)(); // call member function
}
struct foible
{
void say()
{
std::cout << "foible::say" << std::endl;
}
};
int main(void)
{
foible f;
bar(f, &foible::say); // types will be deduced automagically...
}
That came from this answer:
C++ method name as template parameter
But it doesn't do 100% of what I need. How would the above code be re-written so that:
method bar is a public member of a class and not a stand-alone
function
arguments d and f which are getting passed to method bar are
public members of the same class to which bar is a member,
allowing bar to be of type void (void)
object type foible is a class and not a structure (optional)?
[EDIT 1] My own attempt at the rewrite which meets points 1) and 2) is the following, which is wrong:
#include <iostream>
template<class T, void (T::*FType)()>
class foo {
public:
T obj;
FType f;
void bar(void) {
(obj.*f)(); // call member function
} // end bar
}; // end class foo
struct foible
{
void say()
{
std::cout << "foible::say" << std::endl;
}
};
int main(void)
{
foible f;
foo<foible, void (foible::*)()> c;
c.T = f;
c.Ftype = &foible::say;
c.bar(); // types will be deduced automagically...
}
My goal is to have an object of class type 'A' invoke the methods of object of class type 'B', so that when these methods execute the object of type 'B' can use its 'this' pointer to reference its local data. I want to use function pointers inside class type 'A' so that these only need to be specified once, and I don't want one class to have to be derived from another.
You are making that too complicated. Forget about pointers to methods. Currently there is no reason to use them.
Just do something like this:
template<typename F>
void bar(F f) {
doSomething();
f(someArg);
doSomething();
}
int main(void)
{
foible f;
bar([&f](auto x) { f.someMagicMethod(x); } );
return 0;
}
Note this approach is more flexible and readable than playing around with method pointers.
A step by step solution:
all examples uses the following class and foo function
#include <iostream>
class A
{
public:
void foo(){std::cout<<"foo"<<std::endl;}
};
this sample works without template: just calling the calling A::foo with pointer to A and pointer to A::foo:
class B
{
public:
A *a;
void (A::*p)();
void bar()
{
(a->*p)(); //call A::foo
}
};
int main(void)
{
A a;
B b;
b.a = &a;
b.p = &A::foo;
b.bar();
return 0;
}
The following sample added template class T, the pointer to foo method derived from T.
template <class T>
class C
{
public:
T* t;
void (T::*p)();
C(T &o) : t(&o){}
void bar()
{
(t->*p)();
}
};
int main(void)
{
A a;
C<A> c(a);
c.p = &A::foo;
c.bar();
return 0;
}
in the following, the method pointer was templated too, but I don't see how can it be used since you should know how many argument to give it, but anyway:
template <class T, typename F>
class D
{
public:
T* t;
F p;
D(T &o, F pf) : t(&o),p(pf){}
void bar()
{
(t->*p)();
}
};
int main(void)
{
A a;
D<A, void (A::*)()> d(a, &A::foo);
d.bar();
return 0;
}
Consider the following standard CRTP example:
#include <iostream>
template<class Derived>
struct Base {
void f() { static_cast<Derived *>(this)->f(); }
void g() { static_cast<Derived *>(this)->g(); }
};
struct Foo : public Base<Foo> {
void f() { std::cout << 42 << std::endl; }
};
int main() {
Foo foo;
foo.f(); // just OK
foo.g(); // this will stack overflow and segfault
}
If this was regular virtual inheritance I could have mark virtual f and g methods as pure like
struct Base {
virtual void f() = 0;
virtual void g() = 0;
};
and get a compile time error about Foo being abstract. But CRTP offers no such protection. Can I implement it somehow? Runtime check is acceptable too. I thought about comparing this->f pointer with static_cast<Derived *>(this)->f, but didn't manage to make it work.
You can assert at compile time that the two pointers to member functions are different, e.g.:
template<class Derived>
struct Base {
void g() {
static_assert(&Derived::g != &Base<Derived>::g,
"Derived classes must implement g().");
static_cast<Derived *>(this)->g();
}
};
Here is another possibility:
#include <iostream>
template<class Derived>
struct Base {
auto f() { return static_cast<Derived *>(this)->f(); }
auto g() { return static_cast<Derived *>(this)->g(); }
};
struct Foo : public Base<Foo> {
void f() { std::cout << 42 << std::endl; }
};
int main() {
Foo foo;
foo.f(); // just OK
foo.g(); // this will not compile
}
For GCC, it gives a pretty clear error message ("error: use of 'auto Base::g() [with Derived = Foo]' before deduction of 'auto'"), while for Clang, it gives a slightly less readable infinitely recursing template instantiation of Base<Foo>::g, with g instantiating itself but eventually ending in an error.
You could use this solution, you can have pure "non-virtual abstract" function, and it maps as much as possible to CRTP this recommendation of H. Sutter:
template<class Derived>
struct Base
{
void f(){static_cast<Derived*>(this)->do_f();}
void g(){static_cast<Derived*>(this)->do_g();}
private:
//Derived must implement do_f
void do_f()=delete;
//do_g as a default implementation
void do_g(){}
};
struct derived
:Base<derived>
{
friend struct Base<derived>;
private:
void do_f(){}
};
You could consider doing something like this instead. You can make Derived a member and either supply it as a template parameter directly each time you instantiate a Base or else use a type alias as I have done in this example:
template<class Derived>
struct Base {
void f() { d.f(); }
void g() { d.g(); }
private:
Derived d;
};
struct FooImpl {
void f() { std::cout << 42 << std::endl; }
};
using Foo = Base<FooImpl>;
int main() {
Foo foo;
foo.f(); // OK
foo.g(); // compile time error
}
Of course Derived is no longer derived so you might pick a better name for it.
Suppose I have a base class as below:
template <typename T>
class Base {
// implementation
void do_something() { /* ... */ } ;
};
then, I create a Derived class as below, and override the do_something() method:
template <typename T>
class Derived : public Base<T> {
// implementation
void do_something() { /* ... */ } ;
};
I know virtualization does not work in class templates, and I am just hiding the implementation of the methods. but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
my question is, given that static_cast of Derived class to base class gives me the do_something of based class, Is there any way that I can store them as base classes while each has their implementation of do_something() class ?
but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
This is already just not possible in C++. In C++, a vector can only contain objects of the same static type. The only way a vector can contain different types of objects is if their static type is still the same, but they have different dynamic types, but this is type erasure/polymorphism which you said you don't want to use.
I think maybe you need to rethink your requirements, because your question in essence reads: I want to do something, but I don't want to use technique X which is explicitly defined as the only way to do that something in C++!
I did this and it seems to work fine:
#include <iostream>
template <typename T>
struct Base {
virtual void do_something() { std::cout << "Base::do_something()\n"; }
};
template <typename T>
struct Derived : public Base<T> {
virtual void do_something() { std::cout << "Derived::do_something()\n"; }
};
int main() {
Base<int> b;
Derived<int> d;
Base<int> *p;
p = &b;
p->do_something();
p = &d;
p->do_something();
return 0;
}
Output:
Base::do_something()
Derived::do_something()
A little variation of the melpomene's answer (adding a no-template base struct, BaseOfBase, for the Base<T> structs) permit the use of a common vector of base of derived classe of different T types.
A working example
#include <vector>
#include <iostream>
struct BaseOfBase
{ virtual void do_something () = 0; };
template <typename T>
struct Base : public BaseOfBase
{
T val;
void do_something ()
{ std::cout << "Base::do_something() [" << val << "]\n"; };
};
template <typename T>
struct Derived : public Base<T>
{ void do_something()
{ std::cout << "Derived::do_something() [" << this->val << "]\n"; } };
int main ()
{
std::vector<BaseOfBase*> vpbb;
Base<int> bi;
Derived<int> di;
Base<std::string> bs;
Derived<std::string> ds;
bi.val = 1;
di.val = 2;
bs.val = "foo";
ds.val = "bar";
vpbb.push_back(&bi);
vpbb.push_back(&di);
vpbb.push_back(&bs);
vpbb.push_back(&ds);
for ( auto const & pbb : vpbb )
pbb->do_something();
}
When we say virtualization doesn't work in template classes, we don't mean that you can't do virtual functions in a template class, nor does it mean that you cannot override a member function with a specialized version of it.
#melpomene showed an example of overriding in general, and I will show here with specialization:
#include <iostream>
template <typename T>
class Base {
public:
virtual T do_something(T in) { std::cout << "Base::do_something()\n"; return in; }
};
class Derived : public Base<int> {
public:
virtual int do_something(int in) { std::cout << "Derived::do_something()\n"; return in - 1; }
};
void main()
{
Base<int> b;
Derived d;
Base<int> *p = &b;
auto r1 = p->do_something(10);
std::cout << r1 <<std::endl;
p = &d;
auto r2 = p->do_something(10);
std::cout << r2 << std::endl;
}
Which will output
Base::do_something()
10
Derived::do_something()
9
Showing that it perfectly works as expected.
What we do mean when saying that
virtualization does not work in class templates
Basically means that you can't use as a template the derived class when the base is expected.
Consider the above classes Base<T> and Derived, then if we have the following code:
#include <memory>
template <typename T>
void Test(std::unique_ptr<Base<T>> in){ std::cout << "This will not work with derived"; }
void main()
{
Base<int> b;
Derived d;
auto ptr = std::unique_ptr<Derived>(&d);
Test(ptr); // <-- Will fail to compile as an invalid argument
}
it will fail because std::unique_ptr<Derived> does not inherit from std::unique_ptr<Base<T>> although Derived itself inherits from Base<T>.
Is it possible to use SFINAE and std::enable_if to disable a single member function of a template class?
I currently have a code similar to this:
#include <type_traits>
#include <iostream>
#include <cassert>
#include <string>
class Base {
public:
virtual int f() { return 0; }
};
template<typename T>
class Derived : public Base {
private:
T getValue_() { return T(); }
public:
int f() override {
assert((std::is_same<T, int>::value));
T val = getValue_();
//return val; --> not possible if T not convertible to int
return *reinterpret_cast<int*>(&val);
}
};
template<typename T>
class MoreDerived : public Derived<T> {
public:
int f() override { return 2; }
};
int main() {
Derived<int> i;
MoreDerived<std::string> f;
std::cout << f.f() << " " << i.f() << std::endl;
}
Ideally, Derived<T>::f() should be disabled if T != int. Because f is virtual, Derived<T>::f() gets generated for any instantiation of Derived, even if it is never called.
But the code is used such that Derived<T> (with T != int) never gets created only as a base class of MoreDerived<T>.
So the hack in Derived<T>::f() is necessary to make the program compile; the reinterpret_cast line never gets executed.
You could simply specialize f for int:
template<typename T>
class Derived : public Base {
private:
T getValue_() { return T(); }
public:
int f() override {
return Base::f();
}
};
template <>
int Derived<int>::f () {
return getValue_();
}
No you can't rule out a member function with SFINAE. You could do it with specialisation of your Derived class f member function for convertible Ts to int but that would lead to unnecessary duplication of code. In C++17 however you could solve this with use of if constexpr:
template<typename T> class Derived : public Base {
T getValue_() { return T(); }
public:
int f() override {
if constexpr(std::is_convertible<T, int>::value) return getValue_();
return Base::f();
}
};
Live Demo
I would like to do something like:
class A {
public:
void f();
private:
void g() { };
};
class B {
public:
void f();
private:
void g() { };
};
template<typename T>
void T::f() {
g();
}
int main() {
A a;
B b;
a.f();
b.f();
}
however T::f() does not compile.
Possible workarounds could be making f() non-member:
template<typename T>
void f(T* t);
Or using CRTP: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
But is there no C++ syntax to do as above?
EDIT: I have a big function f() whose code is shared by the 2 classes A and B. A and B have the same interface, which f() uses. However, because we are not using runtime polimorphism (i.e, virtual functions), the corpus of f() needs to be instantiated twice at compile time, once for A and once for B. Templates are made exactly for this purpose. The function f(), in my case, should be template function whose template type is the type of *this.
Free function is the correct answer. You should prefer free functions over member functions anyway, for this exact reason: you extend the interface without intruding on the class.
In this case, a free function with an unconstrained template is a bit ugly, because you only need it to work for two cases, not all cases. You should do something like this:
namespace detail
{
template <typename T>
void f(T* t)
{
// implement stuff
}
}
void f(A* x)
{
detail::f(x);
}
void f(B* x)
{
detail::f(x);
}
Now you can restrict access to that function via overloading.
Here is an example using a free function and retaining the instance.f() syntax. The function needs to be marked as a friend in order to access the private methods:
#include <iostream>
namespace details
{
template<class T>
static void f_impl(T* _this)
{
_this->g();
}
}
class A {
public:
template<class T> friend void details::f_impl(T*);
void f()
{
details::f_impl(this);
}
private:
void g()
{
std::cout << "A" << std::endl;
}
};
class B {
public:
template<class T> friend void details::f_impl(T*);
void f()
{
details::f_impl(this);
}
private:
void g()
{
std::cout << "B" << std::endl;
}
};
int main() {
A a;
B b;
a.f();
b.f();
}