SFINAE : Derived class hide base class function depend on T - c++

There are 2 SFINAE snippets that I coded.
They do exactly the same thing.
However, the first one works, while the second doesn't.
Why? (The second is more similar to my real program.)
This code works ( http://coliru.stacked-crooked.com/a/50e07af54708f076 )
#include <iostream>
#include <type_traits>
enum EN{ EN1,EN2 };
template<EN T1> class B{
public: template<EN enLocal=T1> typename
std::enable_if<enLocal==EN1,void>::type test(){ std::cout<<"1"<<std::endl;}
public: template<EN enLocal=T1> typename
std::enable_if<enLocal==EN2,void>::type test(){ std::cout<<"2"<<std::endl; }
};
int main(){
B<EN1> b;
b.test();
}
But this code is uncompilable (http://coliru.stacked-crooked.com/a/28b6afd443b36c7e) :-
#include <iostream>
#include <type_traits>
enum EN{ EN1,EN2 };
class Base{
public: void test(){
std::cout<<"1"<<std::endl;
};
};
template<EN T1> class B : public Base{
public: template<EN enLocal=T1>
std::enable_if_t< enLocal==EN2,void > test(){
std::cout<<"2"<<std::endl;
}
};
int main(){
B<EN1> bEn1; bEn1.test(); //should print 1
//B<EN2> bEn2; bEn2.test(); //print 2
}
I am very new to SFINAE and still learning it via https://stackoverflow.com/a/50562202/.

This code has two issues:
When invoking bEn1.test(); or bEn2.test(); compiler will figure out that name test refers to the function in class B and the set of overloaded functions will include only B::test. This can be fixed by brining name from the base class into derived class:
template<EN T1> class B : public Base{
public: using Base::test;
However now non-template function will be preferred over template function (even when enable_if works) so B<EN2> bEn2; bEn2.test(); will print 1.
In order to make this work again you can introduce yet another overload similar to one in the first example that will invoke function from the base class instead of bringing Base::test name into derived class:
public: template<EN enLocal=T1>
std::enable_if_t< enLocal!=EN2,void > test(){
return Base::test();
}
Another possible C++17-style workaround utilizing if constexpr instead of type traits or SFINAE:
public: template<EN enLocal = T1> void
test()
{
if constexpr(EN2 == enLocal)
{
std::cout<<"2"<<std::endl;
}
else
{
Base::test();
}
}

Depending on what is the real use case, you could also consider some form of tag dispatching:
enum class En {
base, a, b, c
};
template<En Type> void test_impl()
{
if constexpr (Type == En::base)
std::cout << "Base\n";
else if constexpr (Type == En::a)
std::cout << "1\n";
else if constexpr (Type == En::b)
std::cout << "2\n";
else
std::cout << "Default\n";
}
struct Base {
void test() {
std::cout << "Base - ";
test_impl<En::base>();
}
};
template<En Type>
struct Derived : public Base {
void test() {
std::cout << "Derived - ";
test_impl<Type>();
}
};
int main()
{
Base b;
b.test(); // -> "Base - Base"
Derived<En::a> b1;
b1.test(); // -> "Derived - 1"
Derived<En::b> b2;
b2.test(); // -> "Derived - 2"
Derived<En::base> b3;
b3.test(); // -> "Derived - Base"
Derived<En::c> b4;
b4.test(); // -> "Derived - Default"
}

Related

Virtual function with non-shared method

I'm on a personal project and I need to do something unusual. My code is kinda long but the problem comes from the structure so I'll use a very simplified version of the problem.
I have two classes (A and B), with B derived from A.
B uses every attributes and methods of A, including one which creates a modified
clone of the instance of the class.
The problem is that I need to be able to use a method of B after cloning (moo in this case) that doesn't exists in A. I tried to make my methods virtual but it doesn't fix the problem. Is there any way to do this without CRTP ?
I really don't want to use CRTP because it would be really complicated.
(In my real code I have a chain of 4 class inheritances, and all 4 are already templated)
#include <iostream>
class A
{
public:
/*Common function*/
virtual void foo(){
std::cout << "call from A" << std::endl;
}
A* clone(){
/*
...
... Code I don't want to write again for B
...
*/
return this;
}
};
class B: public A
{
public:
/*Common function*/
virtual void foo(){
std::cout << "call from B" << std::endl;
}
/*Not derived from A*/
void moo(){ //Doesn't work even with virtual keyword
std::cout << "only exist in B" << std::endl;
}
};
int main(int argc, char const *argv[])
{
auto tB = new B();
tB->foo();
tB->moo();
tB->clone()->foo();
tB->clone()->moo();
return 0;
}
Compilator:
error: 'class A' has no member named 'moo'; did you mean 'foo'?
38 | tB->clone()->moo();
| ^~~
| foo
I'm not English so sorry if it's unclear.
Well, according to the comments, my research and how I think c++ works, I give up finding something that looks like virtual methods and still be satisfying.
So I resolved to use the CRTP, for those who are interested here's the code of my model of a 3 (I deleted one) inherited class CRTP with an additional type template argument :)
#include <iostream>
//CRTPI = "CRTP Interface", used for inheritances between CRTPs
template<typename Derived, typename T>
class CRTPI_A
{
protected:
T x = 0;
public:
T getX(){
return x;
}
Derived* clone(){
/*
...
... Code I don't want to write again for B and it's childs
...
*/
return new Derived();
}
};
template<typename Derived, typename T>
class CRTPI_B: public CRTPI_A<Derived, T>
{
public:
//Only for B and its childs
void iwd(){
std::cout << "Hi, i'm a B child !" << std::endl;
}
};
template<typename Derived, typename T>
class CRTPI_C: public CRTPI_B<Derived, T>{};
template<typename T>
class A: public CRTPI_A<A<T>, T>
{
public:
A(){};
A(T z){
this->x = z;
}
void foo(){
std::cout << "call from A" << std::endl;
}
};
template<typename T>
class B: public CRTPI_B<B<T>, T>
{
public:
B(){};
B(T z){
this->x = z;
}
void foo(){
std::cout << "call from B" << std::endl;
}
//Not in CRTP interface so won't be inherited by C
void UwU(){
std::cout << "I'm exclusive to B" << std::endl;
}
};
template<typename T>
class C: public CRTPI_C<C<T>, T>
{
public:
C(){};
C(T z){
this->x = z;
};
void foo(){
std::cout << "call from C" << std::endl;
}
};
int main(int argc, char const *argv[])
{
auto tA = new A<char>('A');
auto tB = new B<int>(2);
auto tC = new C<float>(420.69);
tA->foo();
tA->clone()->foo();
printf("\n");
tB->foo();
tB->iwd();
tB->clone()->foo();
tB->clone()->iwd();
tB->UwU();
printf("\n");
tC->foo();
tC->iwd();
// tC->UwU(); //Won't work but that's planned
std::cout << "\n" << tA->getX() << ":" << tB->getX() <<":" << tC->getX() << std::endl;
return 0;
}
Note that, here, the CRTP interface for C is optional because it has no child class and no exclusive methods, so we can just write:
template<typename T>
class C: CRTPI_B<C<T>, T>
{
...
}

Get parent of type T in a template function

I want to find out what is the parent of the type class T in a template function, suppose I've the following classes:
class A{
...
}
class B: public A{
...
}
class C: public B{
...
}
template<typename T>
size_t getBaseHashCode()
{
return typeid(base_of(T)).hashcode();
}
int main()
{
A a;
C c;
size_t size = getBaseHashCode<C>();// must return hashcode of class B
}
is there anyway to find parent of type T and implement base_of function?
Edit:
indeed what I want to do is:
I've factory class which creates objects for me:
template <typename B>
class Factory{
public:
template <typename D>
void registerType(std::string name)
{
static_assert(std::is_base_of<B, D>::value, "class doesn't derive from the base");
table_[name] = &createFunc<D>;
}
B* create(std::string name)
{
const auto it = table_.find(name);
if(it != table_.end())
return it->second();
FILE_LOG(logERROR) << "unidentified option, acceptable options are:";
for(auto const &m : list())
FILE_LOG(logERROR) << '\t' << m;
return nullptr;
}
std::vector<std::string> list()
{
std::vector<std::string> lst;
for(auto const &iter : table_)
lst.push_back(iter.first);
return lst;
}
private:
template<typename D>
static B* createFunc()
{
return new D();
}
typedef B* (*PCreateFunc)();
std::map<std::string, PCreateFunc> table_;
};
in the registerType function I want to set some properties of type D or it's parent and then in the create function, I want to create objects based on that.
You might also consider using some parent wrappers to automatize typedefing:
#include <type_traits>
#include <typeinfo>
#include <iostream>
template <class P>
struct base: P {
using base_type = P;
};
struct A{ };
struct B: base<A>{ };
struct C: base<B>{ };
template <class T>
auto base_of(T) -> typename T::base_type;
template <class T>
using base_of_t = decltype(base_of(std::declval<T>()));
int main() {
std::cout << typeid(base_of_t<C>).name() << std::endl;
}
Output:
1B
Output of c++filt -t 1B:
B
[live demo]
Note it still does not deal with multiple inheritance
You can use a couple of functions declarations that you don't have to define.
It follows a minimal, working example:
#include<utility>
#include<typeinfo>
#include<iostream>
class A{};
class B: public A{};
class C: public B{};
B base_of(const C &);
A base_of(const B &);
template<typename T>
void getBaseHashCode() {
std::cout << typeid(decltype(base_of(std::declval<T>()))).name() << std::endl;
}
int main() {
getBaseHashCode<B>();
getBaseHashCode<C>();
}
It exploits the fact that, in this case, you have exact matches during the invokations. It's quite weak a solution, but works with the example code in the question.
That said, I agree on the fact that the whole question looks like an XY-problem.
EDIT
As mentioned by #Jarod42 in the comments, a more idiomatic (and verbose) way would be by using traits.
It follows a minimal, working example:
#include<typeinfo>
#include<iostream>
class A{};
class B: public A{};
class C: public B{};
template<typename> struct base_of;
template<> struct base_of<B> { using type = A; };
template<> struct base_of<C> { using type = B; };
template<typename T>
void getBaseHashCode() {
std::cout << typeid(typename base_of<T>::type).name() << std::endl;
}
int main() {
getBaseHashCode<B>();
getBaseHashCode<C>();
}
This will solve also the problem due to multiple inheritance. The designer of base_of specializations will be in charge to promote one of the base classes to the role of preferred one.

C++: Inheriting from template class with possible varying constructor arguments

Suppose we have the following sample classes:
class A {
public:
explicit A(int foo) { }
void test() {
cout << "I'm in A" << endl;
}
};
class B {
public:
explicit B(string bar) { }
void test() {
cout << "I'm in B" << endl;
}
};
I would like to define a child class to inherit from a templatized class that
could be specialized as one of either A or B. The problem I'm facing is that A
and B have different constructor arguments, so building Child's constructor is
proving to be a bit vexing. Things work if I do something like the following:
template <class ParentClass>
class Child : public ParentClass {
public:
Child<B>() : ParentClass("foo") {
}
};
int main() {
Child<B> c;
c.test();
return 0;
}
However, I'd like to also be able to do something like Child<A> c. Is this
possible?
Thanks!
You may specialize for each class:
template <class ParentClass>
class Child : public ParentClass {
public:
Child();
};
template <>
Child<A>::Child() : A(42) {}
template <>
Child<B>::Child() : B("42") {}
Demo
You can try a templated constructor as follows:
#include <iostream>
using namespace std;
class A {
public:
explicit A(int foo) { }
void test() {
cout << "I'm in A" << endl;
}
};
class B {
public:
explicit B(string bar) { }
void test() {
cout << "I'm in B" << endl;
}
};
template <class Parent>
class Child
: public Parent {
public:
template <class... Args>
Child(Args... args)
: Parent(args...) {
}
};
int main() {
Child<A> a_child(42);
Child<B> b_child("42");
a_child.test();
b_child.test();
}
You can use a delegating constructor if you want to let the user decides the parameters:
template <class ParentClass>
class Child : public ParentClass {
public:
using ParentClass::ParentClass;
};

How to declare a template method of a template base class using 'using'?

Two methods for accessing template base class members are described here. When the base class member itself is a template, accessing it using the first method (this->) above is described here. Is there a way to use the second method (using xxxx) in this scenario as well?
For example, in the code below, is it possible to replace "????" with something to make the code work?
using namespace std;
template<typename T> class base
{
public:
template<bool good> void foo()
{
cout << "base::foo<" << boolalpha << good << ">()" << endl;
}
};
template<typename T> class derived : public base<T>
{
public:
using ????
void bar()
{
foo<true>();
}
};
Just for the record, even though it does not provide any answer or workaround, but I am currently working with VS Express 2013, and I can assure you that
#include <iostream>
template<typename T> class base
{
public:
template<bool good> void foo()
{
std::cout << "base::foo<" << good << ">()" << std::endl;
}
};
template<typename T> class derived : public base<T>
{
public:
void bar()
{
foo<true>();
}
};
struct A{};
void main() {
derived<A> a;
a.bar();
}
works perfectly fine...

Template specialization of inherited member function

We would like to specialize member functions of a base class. However, it does not compile. Does anybody know of any alternative that does compile?
Here is an example
struct Base
{
template<typename T>
void Foo()
{
throw "Foo() is not defined for this type";
}
};
struct Derived : public Base
{
template<>
void Foo<int>() { cout << "Foo<int>()" << endl; } // compile error (cannot specialize members from a base class)
template<>
void Foo<double>() { cout << "Foo<double>()" << endl; } // compile error (cannot specialize members from a base class)
};
Eventually, we solved it using overloading.
Here is how the base class looks like
struct Base
{
template<typename T>
class OfType {}
template<typename T>
void Foo(OfType<T>) { static_assert(false, "Foo is not implemented for this type. Please look in the compiler error for more details."); }
};
struct Derived : public Base
{
using Base::Foo;
void Foo(OfType<int>) { // here comes logic for ints }
void Foo(OfType<double>) { // here comes logic for doubles }
};
Here is an example of client code that uses Foo()
template<typename S>
class ClassThatUsesFoo
{
private: S s;
template<typename T>
void Bar(T item)
{
s.Foo(Base::OfType<T>()); // this is the code that uses Foo
DoSomeStuffWithItem(item);
}
};
void main()
{
ClassThatUsesFoo<Derived> baz;
baz.Bar(12); // this will internally use Foo for ints
baz.Bar(12.0); // this will use Foo for doubles
baz.Bar("hello world"); // this will give a verbose compile error
}
This will compile, except for the call to Foo<char>():
#include <iostream>
#include <string>
using namespace std;
struct Base
{
template<typename T>
void Foo()
{
throw "Foo() is not defined for this type";
}
};
struct Derived : public Base
{
template<typename T> void Foo();
};
template<>
void Derived::Foo<int>() { cout << "Foo<int>()" << endl; }
template<>
void Derived::Foo<double>() { cout << "Foo<double>()" << endl; }
int main()
{
Derived derived;
// this is client code
derived.Foo<int>();
derived.Foo<double>();
derived.Foo<char>(); // this throws
}
If you want the call to Foo<char>() -- or any type not specifically specialized by you -- then this works. If you want a non-specialized implementation that works for all types, then you need to add a non-specialized implementation of Foo() as well:
template<typename T>
void Derived::Foo() { cout << "generic" << endl; }
In response to the discussion with Alex (see comments of the answer of John Dibling), this is what I meant (SSCCE):
#include <iostream>
using namespace std;
struct Base
{
template<typename T>
void Foo()
{
//static_assert(false, "Foo() is not defined for this type");
throw "Foo() is not defined for this type";
}
};
// you can add as many specializations in Base as you like
template <>
void Base::Foo<char>() { cout << "Base::Foo<char>()" << endl; }
struct Derived : public Base
{
// just provide a default implementation of Derived::Foo
// that redirects the call to the hidden Base::Foo
template < typename T >
void Foo()
{ Base::Foo<T>(); }
};
// the specializations for Derived
template<>
void Derived::Foo<int>() { cout << "Foo<int>()" << endl; }
template<>
void Derived::Foo<double>() { cout << "Foo<double>()" << endl; }
struct Derived_wo_specialization : public Base
{
/* nothing */
};
int main()
{
Derived d;
d.Foo<char>();
d.Foo<double>();
Derived_wo_specialization dws;
dws.Foo<char>();
dws.Foo<double>();
}