I am trying to implement a template class that is intended to be used both as a base for deriving and for use as a concrete class if the template parameters are right.
What I want to achieve is that if a method of the template class cannot be instantiated, but a deriving class provides an implementation, that this is OK.
But if the template can be fully instantiated that the class is valid on it's own.
Example:
// interface class
class A
{
public:
virtual void foo() = 0;
virtual ~A() {}
};
// template class
template <typename T>
class B : public A
{
public:
/* if this tenplate can be instantiated */
foo()
{
T obj;
std::cout << obj;
}
/* else
foo() = 0;
*/
};
// concrete classes
// will work on it's own
typedef B<std::string> C;
class D : public B<void>
{
// B<void>::foo won't instantiate on it's own
// so we provide help here
foo() {}
};
int main(int argc, char const *argv[])
{
A * = new C(); // all good
A * = new D(); // error: cannot instantiate B<void>::foo
return 0;
}
Is there a way to achieve such an effect?
Using SFINAE, you may do something like:
namespace detail
{
// an helper for traits
template <typename T>
decltype(T{}, std::cout << T{}, std::true_type{})
helper_has_default_constructor_and_foo(int);
template <typename T>
std::false_type helper_has_default_constructor_and_foo(...);
// the traits
template <typename T>
using has_default_constructor_and_foo = decltype(helper_has_default_constructor_and_foo<T>(0));
// genaral case (so when traits is false)
template <typename T, typename = has_default_constructor_and_foo<T>>
struct C : public A {};
// specialization when traits is true
template <typename T>
struct C<T, std::true_type> : public A
{
void foo() override { std::cout << T{}; }
};
}
And finally:
template <typename T>
class B : public detail::C<T>
{
};
live demo
You could specialize for B<void>:
// template class
template <typename T>
class B : public A
{
public:
virtual void foo()
{
T obj;
std::cout << obj;
}
};
template <>
class B<void> : public A
{
public:
virtual void foo() = 0;
};
You must specialise B<> and cannot use SFINAE (on the member foo). SFINAE only works on templates, but member function templates cannot be virtual.
There are different ways you can achieve the specialization, but the most straightforward is the simple and explicit
template<typename T>
class B : public A
{
/* ... */ // not overridden foo() by default
};
template<>
class B<WhatEver> : public A
{
virtual foo();
};
Related
Let's say I have two template classes Foo<A,C,E> and Foo<A,B,C,D,E,F>. I want the former to automatically be derived from the latter. How can that be done?
My motivation for this: I want to use Foo<A,C,E> and Foo<A,B,D>. They need to be placed in some base class declaration. But if I homogenize them into some FooBase base class, it will lose all the properties of Foo<Ts...> (which has template member functions, so I cannot make them virtual in FooBase and define the overrides in the Foo derived classes). So if I just use Foo<A,B,C,D,E,F> as the base class definition, then everything should work out fine. Below illustrates the problem at hand:
struct FooBase { // Fruitless attempt to homegenize A and B defined below.
// template <int N> virtual void run() = 0; // No good, of course
};
template <typename... Ts>
struct Goo {
template <int N> void run() { } // This needs to be called by Foo<Ts...>
};
template <typename... Ts>
struct Foo : Goo<Ts...>, FooBase {
// template <int N> virtual void run() override { Goo<Ts...>::run<N>(); }
};
using A = Foo<int, char>;
using B = Foo<double, char>;
struct Thing {
FooBase *foo1, *foo2;
Thing (FooBase* f, FooBase* g) : foo1(f), foo2(g) { }
template <int N> void run() { foo1->run<N>(); foo2->run<N>(); }
};
int main() {
A* a = new A;
B* b = new B;
Thing thing(a,b);
thing.run<5>();
}
I'm trying to make a template generic with a struct and substruct,
but my code fail to infer the correct template.
this is the abstraction of my code
#include <iostream>
using namespace std;
struct A{
};
struct B{
};
struct AA:public A{
};
struct BB:public B{
};
template<class container>
class Base{
};
template<class container>
class Derived:Base<container>{
Derived() = delete;
};
template<>
class Derived<A>:Base<A>{
};
template<>
class Derived<B>:Base<B>{
};
int main() {
Derived<AA> a;
return 0;
}
and got error
error: call to deleted constructor of 'Derived<AA>'
i wish struct A and its subclass can be used with
template<>
class Derived<A>:Base<A>{
};
how can I do it, or what material should I refer to?
thx for help!
You can use the partial specialization like
// primary template
template<class container, class = void>
class Derived : Base<container> {
Derived() = delete;
};
// partial specialization for A and its derived classes
template<class container>
class Derived<container, std::enable_if_t<std::is_base_of_v<A, container>>> : Base<container> {
};
and also full specialization if necessary.
// full specialization for B
template<>
class Derived<B, void> : Base<B> {
};
LIVE
I'm trying to specialize member functions of a template class based on the type of template. In particular I'd like to have specializations based on polymorphic types. I've been struggling with the syntax. Here is my try which obviously produces the error: two or more data types in declaration of doSomething()
class Base {};
class Derived : public Base {};
template<typename T>
class MyClass
{
public:
void doSomething();
};
template<>
template<typename T>
typename std::enable_if<std::is_base_of<Derived, T>::value>::type
void MyClass<T>::doSomething()
{
// Do something with Derived type
}
template<>
template<typename T>
typename std::enable_if<std::is_base_of<Base, T>::value &&
!std::is_base_of<Derived, T>::value>::type
void MyClass<T>::doSomething()
{
// So something with Base type
}
template<>
template<typename T>
typename std::enable_if<!std::is_base_of<Derived, T>::value>::type
void MyClass<T>::doSomething()
{
// Do something with all other types
}
Compilation gives..
error: two or more data types in declaration of 'doSomething'
BTW, I did get the following to compile, but the specialization did not work as expected at runtime. Base and derived types end up going through the non-specialized version of doSomething().
class Base {};
class Derived : public base {};
template<typename T>
class MyClass
{
public:
void doSomething()
{
// Do something for non-specialized types
}
};
template<>
void MyClass<Derived>::doSomething()
{
// Do something with Derived type
}
template<>
void MyClass<Base>::doSomething()
{
// So something with Base type
}
What would be the correct syntax?
You cannot specialize doSomething simply because it's not a template. MyClass is a template and you can specialize the class, each specialization having one doSomething. If that's not what you want then you need to make doSomething template overloads and, for the SFINAE to work, the SFINAE check must be done on the doSomething template parameter, not on the MyClass parameter. Lastly your checks are wrong.
So here is my version:
template<class T> struct MyClass
{
template <class U = T>
auto foo() -> std::enable_if_t<std::is_base_of_v<Base, U>
&& !std::is_base_of_v<Derived, U>>
{
foo_base();
}
template <class U = T>
auto foo() -> std::enable_if_t<std::is_base_of_v<Derived, U>>
{
foo_derived();
}
template <class U = T>
auto foo() -> std::enable_if_t<!std::is_base_of_v<Base, U>>
{
foo_else();
}
};
And here is a battery of tests:
class Base {};
class Derived : public Base {};
class A : Base {};
class B : Derived {};
class X {};
auto test()
{
MyClass<Base>{}.foo(); // foo_base
MyClass<Derived>{}.foo(); // foo_derived
MyClass<A>{}.foo(); // foo_base
MyClass<B>{}.foo(); // foo_derived
MyClass<X>{}.foo(); // foo_else
}
And of course I must mention the C++17 clean solution:
template<class T> struct MyClass
{
auto foo()
{
if constexpr (std::is_base_of_v<Derived, T>)
foo_derived();
else if constexpr (std::is_base_of_v<Base, T>)
foo_base();
else
foo_else();
}
};
Another possible solution pass through a ForFoo template class, that define a foo() method, with a couple of specializations for Base only and Derived classes. So MyClass<T> can inherit from ForFoo<T>.
I mean... if you define a ForFoo set of template classes as follows
template <typename T, typename = void>
struct ForFoo
{ void foo () { std::cout << "other type" << std::endl; } };
template <typename T>
struct ForFoo<T,
typename std::enable_if<std::is_base_of<Base, T>::value
&& ! std::is_base_of<Derived, T>::value>::type>
{ void foo () { std::cout << "Base type" << std::endl; } };
template <typename T>
struct ForFoo<T,
typename std::enable_if<std::is_base_of<Derived, T>::value>::type>
{ void foo () { std::cout << "Derived type" << std::endl; } };
MyClass simply become
template <typename T>
struct MyClass : public ForFoo<T>
{ };
The following is a full working C++11 example
#include <iostream>
#include <type_traits>
class Base {};
class Derived : public Base {};
class A : Base {};
class B : Derived {};
class X {};
template <typename T, typename = void>
struct ForFoo
{ void foo () { std::cout << "other type" << std::endl; } };
template <typename T>
struct ForFoo<T,
typename std::enable_if<std::is_base_of<Base, T>::value
&& ! std::is_base_of<Derived, T>::value>::type>
{ void foo () { std::cout << "Base type" << std::endl; } };
template <typename T>
struct ForFoo<T,
typename std::enable_if<std::is_base_of<Derived, T>::value>::type>
{ void foo () { std::cout << "Derived type" << std::endl; } };
template <typename T>
struct MyClass : public ForFoo<T>
{ };
int main ()
{
MyClass<Base>{}.foo(); // Base
MyClass<Derived>{}.foo(); // Derived
MyClass<A>{}.foo(); // Base
MyClass<B>{}.foo(); // Derived
MyClass<X>{}.foo(); // other
}
I have base class template, on that I'm making some another class, which are specialized versions of my base class. I know how to exclude some methods from particular specialization case, but is there any possibility to make that for class's members? Example code, of what I want to achieve:
template<typename T>
class Base {
This variable exists only when T==integer VARIABLE;
}
template <Typename T>
WithVariable = using Base<int>;
template <Typename T>
Without = using Base<double>
I think that I should use std::enable in some way, but using it makes possible to make VARIABLE of type "void", when I don't want that variable. That is still not the situation I want to achieve.
Can you just specialise the class without the unwanted members?
template <typename T>
class Base {
public:
T t;
};
template <>
class Base<int> {
};
int main() {
Base<int> foo;
foo.t = 42; // Error: no member named 't' in 'Base<int>'
}
One possible way to do this is to inherit conditionally. Take a look:
struct BaseWithVariable {
int n {42};
};
struct BaseNoVariable {};
template <typename T>
struct Base : std::conditional<std::is_same<T, int>::value, BaseWithVariable, BaseNoVariable>::type {};
and usage:
Base<int> b {};
Base<double> d {};
std::cout << b.n << std::endl;
std::cout << d.n << std::endl; // error
You can also write an explicit specialization for your type, but if you have a group of types (like integers or type derived from specific base) which should have different members than general type, this solution can be helpful.
You can use a base for base that use SFINAE
#include <type_traits>
template <typename, typename = void>
struct base_of_base;
template <typename T>
struct base_of_base<T, typename std::enable_if<std::is_integral<T>::value>::type>
{ int var; };
template <typename T>
struct base_of_base<T, typename std::enable_if<!std::is_integral<T>::value>::type>
{ };
template <typename T>
class base : public base_of_base<T>
{ };
int main()
{
base<int> bi;
base<long> bl;
base<float> bf;
base<double> bd;
bi.var = 1; // OK
bl.var = 1; // OK
// bf.var = 1; // error: ‘class base<float>’ has no member named ‘var’
// bd.var = 1; // error: ‘class base<double>’ has no member named ‘var’
}
How about deleteing the functions from specialisations of the class?
template <typename T>
class Base {
public:
void notUseful();
};
template<typename T>
void Base<T>::notUseful(){
std::cout << "not useful" << std::endl;
return;
}
template <>
void Base<int>::notUseful() = delete;
How would you go about filling-in a method if a base class doesn't provide it. I'd like to reuse the base class method if it is provided.
E.g.:
#include <iostream>
struct Base0 { };
struct Base1 { void m() { std::cout<<"Base1\n"; } };
template<typename T>
struct Derived : public T {
//if T doesn't provide m, define it here, otherwise reuse the base class method
void m(){ /*? std::cout<<"Derived\n"; ?*/ }
};
int main(){
Derived<Base0> d0;
d0.m(); //should print "Derived"
Derived<Base1> d1;
d1.m(); //should print "Base1"
}
With SFINAE, you may do
template<typename T>
struct Derived : public T {
private:
template <typename U = T>
auto m_impl(int) -> decltype(std::declval<U&>().m()){ this->U::m(); }
template <typename U = T>
void m_impl(... ) { std::cout<<"Derived\n"; }
public:
void m() { m_impl(0); }
};
Demo
In order to be general, you should define the function anyway under a different signature:
template<typename T>
struct Derived : public T
{
auto m(std::false_type) { std::cout<<"Derived\n"; }
};
Then you can use the methods given in this thread in order to check whether the base class has the function m():
template <typename...>
using void_t = void;
template <typename T, template <typename> class D, typename = void>
struct detect : std::false_type {};
template <typename T, template <typename> class D>
struct detect<T, D, void_t<D<T>>> : std::true_type {};
template <typename T>
using has_m = decltype(std::declval<T>().m());
Finally, you can use that as
template<typename T>
struct Derived : public T
{
auto m(std::true_type) { return T::m(); }
auto m(std::false_type) { std::cout<<"Derived\n"; }
auto m() { return m(detect</* const */ T, has_m>{}); }
^^^^^^^^^^
//if m() is const
};
DEMO
As Aslay Berby already said this is probably not the way that you would like to go. If you want to implement something like traits or policy-based design, the following code might be what you are looking for. In fact such designs are used quite commonly and have also idiomatic value.
#include <iostream>
using namespace std;
struct StandardTraits {void foo() {cout << "standard" << endl;}};
struct Traits1 {void foo() {cout << "traits1" << endl;}};
struct Traits2 {void foo() {cout << "traits2"<< endl;}};
template<typename T = StandardTraits>
class SomeClass
{
public:
typedef T Traits;
void useTraits() {traits.foo();}
private:
Traits traits;
};
int main() {
SomeClass<> x;
SomeClass<Traits1> y;
SomeClass<Traits2> z;
x.useTraits();
y.useTraits();
z.useTraits();
return 0;
}
// output:
// standard
// traits1
// traits2
See also: https://en.wikipedia.org/wiki/Policy-based_design