I'm trying to deduct a template of a function based on the class of the object invoking the function. How can I do this?
#include <type_traits>
struct B;
template<typename T>
bool f(const T*) { return std::is_same<T, B>::value; }
struct A {
bool g() { return f(this); }
};
struct B:A {};
int main() {
B b_obj;
return b_obj.g(); // returns false
}
Making g virtual doesn't help either.
How can I make b_obj.g() return true?
Both the below ways require modification of the code:
Runtime polymorphism (preferred IMO)
Make the callable function a non-template virtual method of base class. i.e.
struct A {
virtual bool f () { /* code */ }
bool g() { return f(); } // no argument to be passed now!
};
struct B : A { bool f () override { /* code */ } };
Static polymorphism (using CRTP)
template<class Child>
struct A {
bool g() { return f(static_cast<Child*>(this); }
};
struct B : A<B> {};
Related
As we know in CRTP the derived class inherit base, as final inheritance.
What if we want make the derived class not-final but the 'overriding' functions is 'final'?
Is there any way to make it with static_assert?
Code sample:
template <typename D>
struct A
{
int f()
{
return static_cast<D*>(this)->g();
}
int g();
};
struct B : A<B> // usually final, but we want it inheritable
{
int g() // but this should be 'final'
{
// TODO: ???
return 1;
}
};
struct C : B
{
int g() // this is bad
{
return 2;
}
int h(); // this is permissive
};
#include <iostream>
template <typename D>
void f(A<D>& x)
{
std::cout << x.f() << std::endl;
}
int main()
{
B b;
C c;
f(b); // OK, it's 1
f(c); // BAD, it's 1
return 0;
}
You can use final for two purposes.
From https://en.cppreference.com/w/cpp/language/final
specifies that a virtual function cannot be overridden in a derived class or that a class cannot be inherited from.
You can use
struct B : A<B>
{
virtual int g() final
{
return 1;
}
};
to allow other classes to derive from B but not able to override g().
Another potential side benefit of using final is that an optimizing compiler might be able to resolve the function call at compile time instead of resolving at run time (Thanks #JesperJuhl).
I came up with a solution by using private tag in function signature:
template <typename D>
struct A
{
struct internal_tag
{};
int f()
{
return static_cast<D*>(this)->g({});
}
int g(internal_tag);
};
struct B : A<B>
{
int g(internal_tag)
{
return 1;
}
private:
using A<B>::internal_tag;
};
struct C : B
{
// int g(internal_tag) // int g(internal_tag) is prohibited
// {
// return 2;
// }
int h();
};
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;
}
#include <iostream>
using namespace std;
class c1 {
public:
void f1() { std::cout << "In f1\n"; }
};
class c2 {
public:
void f2() { std::cout << "In f2\n"; }
};
template<typename T>
class C: public c1, c2 {
public:
void f() {
};
};
int main() {
C<c2> c;
c.f();
return 0;
}
is there any way based on T the function f in C can be mapped to function f1 in c1 and f2 in c2? I am not clear how function f that can be used as a wrapper around f1 and f2 when i am pointing to a specific class using T
Note: I cannot modify class c1 and c2. its out of my scope.
You can use constexpr if from C++17. e.g.
void f() {
if constexpr (std::is_same_v<T, c1>)
f1();
else
f2();
}
LIVE
Note that constexpr if is evaluated at compile-time, as #skypjack commented, for this case, it's pretty fine to be evaluated at run-time too. So the following code works fine too:
void f() {
if (std::is_same_v<T, c1>)
f1();
else
f2();
}
Yes, you can write a template like that. In several ways in fact. If you want to keep C as it is, then it's a simple matter of adding a type trait which contains a pointer to a member function
Live Example
template<typename> struct which_member;
template<> struct which_member<c1> {
static constexpr void (c1::* func)() = &c1::f1;
};
template<> struct which_member<c2> {
static constexpr void (c2::* func)() = &c2::f2;
};
void f() {
(static_cast<T*>(this)->*which_member<T>::func)();
}
The key is here (static_cast<T*>(this)->*which_member<T>::func)();. We cast this to the appropriate type pointer, then use the trait to retrieve the pointer to a member. And finally we use the access operator ->* on these two operands to obtain a callable expression. Which we then call (the outer ()).
The cast isn't strictly needed, but I think the error message is more descriptive of the problem if you pass something that isn't a base class of C as the type parameter.
You can specialise template:
#include <iostream>
using namespace std;
class c1{
public:
void f1(){std::cout<<"In f1\n";}
};
class c2{
public:
void f2(){std::cout<<"In f2\n";}
};
template <typename T>
class C:public c1, c2 {
public:
void f()
{
};
};
template<> class C<c1>:public c1, c2 {
public:
void f()
{
c1::f1();
};
};
template<> class C<c2>:public c1, c2 {
public:
void f()
{
c2::f2();
};
};
int main()
{
C<c2> c;
c.f();
return 0;
}
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 have a method foo in class C which either calls foo_1 or foo_2.
This method foo() has to be defined in C because foo() is pure virtual in BaseClass and I actually
have to make objects of type C. Code below:
template <class T>
class C:public BaseClass{
void foo() {
if (something()) foo_1;
else foo_2;
}
void foo_1() {
....
}
void foo_2() {
....
T t;
t.bar(); // requires class T to provide a method bar()
....
}
};
Now for most types T foo_1 will suffice but for some types foo_2 will be called
(depending on something()). However the compiler insists on instantiating both foo_1
and foo_2 because either may be called.
This places a burden on T that it has to provide
a bar method.
How do I tell the compiler the following:
if T does not have bar(), still allow it as an instantiating type?
you could use boost.enable_if. something like this:
#include <boost/utility/enable_if.hpp>
#include <iostream>
struct T1 {
static const bool has_bar = true;
void bar() { std::cout << "bar" << std::endl; }
};
struct T2 {
static const bool has_bar = false;
};
struct BaseClass {};
template <class T>
class C: public BaseClass {
public:
void foo() {
do_foo<T>();
}
void foo_1() {
// ....
}
template <class U>
void foo_2(typename boost::enable_if_c<U::has_bar>::type* = 0) {
// ....
T t;
t.bar(); // requires class T to provide a method bar()
// ....
}
private:
bool something() const { return false; }
template <class U>
void do_foo(typename boost::enable_if_c<U::has_bar>::type* = 0) {
if (something()) foo_1();
else foo_2<U>();
}
template <class U>
void do_foo(typename boost::disable_if_c<U::has_bar>::type* = 0) {
if (something()) foo_1();
// I dunno what you want to happen if there is no T::bar()
}
};
int main() {
C<T1> c;
c.foo();
}
You could create an interface for foo_1 and foo_2, such as:
class IFoo
{
public:
virtual void foo_1()=0;
virtual void foo_2()=0;
};
template <typename T>
class C : public BaseClass, public IFoo
{
void foo()
{
if (something())
foo_1();
else
foo_2();
}
};
template <typename T>
class DerivedWithBar : C<T>
{
public:
void foo_1() { ... }
void foo_2()
{
...
T t;
t.bar(); // requires class T to provide a method bar()
...
}
};
template <typename T>
class DerivedNoBar : C<T>
{
public:
void foo_1() { ... }
void foo_2() { ... }
};
I think the easiest way is to simply write a separate function template that 'C' can call:
template <class T>
void call_bar(T& /*t*/)
{
}
template <>
void call_bar<Something>(Something& t)
{
t.bar();
}
The original 'C' class can be modified accordingly:
void foo_2() {
....
T t;
call_bar(t); // does not require T to provide bar()
....
}
This has the downside that you have to explicitly define which types of T provide a bar method, but that's pretty much inevitable unless you can determine something at compile-time about all the types that do provide a bar method in their public interface or modify all these bar-supporting types so that they do share something in common that can be determined at compile-time.