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
Related
I have a class A that is a template, and I want to specialize the method foo() if the class is a std::vector<T> with T generic, I am getting the error: invalid use of incomplete type. I'd like to avoid writing all specializations for all possible vectors.
#include <iostream>
#include <vector>
template<typename V>
struct A {
void foo() {
std::cout << "A<V>\n";
}
};
template<typename T>
void A<std::vector<T>>::foo() {
std::cout << "A<V<T>>\n";
}
int main() {
C<int> a;
C<std::vector<int>> b;
return 0;
}
If foo() doesn't depends from other elements of A, you can inherit it through a base class and specialize the base class.
I mean something as follows
template <typename>
struct Base
{ void foo() { std::cout << "A<V>\n"; } };
template <typename ... Ts>
struct Base<std::vector<Ts...>>
{ void foo() { std::cout << "A<V<Ts...>>\n"; } };
template <typename T>
struct A : public Base<T>
{ };
Another possible solution is tag-dispatching: develop two foo() functions an "enable" the correct one, according the needs.
For example
template <typename>
struct is_vector : public std::false_type
{ };
template <typename ... Ts>
struct is_vector<std::vector<Ts...>> : public std::true_type
{ };
template <typename T>
struct A
{
void foo (std::true_type) { std::cout << "A<V<Ts...>>\n"; }
void foo (std::false_type) { std::cout << "A<V>\n"; }
void foo () { foo(is_vector<T>{}); }
};
Just using c++20 contrians:
template <typename V>
struct A {
void foo() { std::cout << "A<V>\n"; }
void foo() requires (std::same_as<V, std::vector<typename V::value_type>>) {
std::cout << "A<V<T>>\n";
}
};
Then this works:
A<int>{}.foo(); // call normal one
A<std::vector<int>>{}.foo(); // call specialized one
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 a class “A” which exposes the template method foo.
Foo has a standard implementation which works fine with B,C. It also has a special implementation for D.
class A
{
template<typename T>
void foo()
{
//standard implementation
}
template<>
void foo<D>
{
//special implementation
}
}
class B{};
class C{};
class D{};
int main()
{
A<B> a1;
A<C> a2;
A<D> a3;
}
Now, I need to add the class E, which requires for "foo" the same special implementation as D.
Is there a way to say something like: For all the types use the standard foo. For D,E (and so on) the special implementation.
class A
{
template<typename T>
void foo()
{
//standard implementation
}
template<>
void foo<D && E> <-- PseudoCode - It doesn't work
{
//special implementation
}
}
class B{};
class C{};
class D{};
class E{};
int main()
{
A<B> a1;
A<C> a2;
A<D> a3;
A<E> a4;
}
I was thinking to use the trait classes. But I was hoping there is something simpler to achieve this.
Thanks
Using Walter Brown's (C++1z) void_t.
#include <iostream>
#include <type_traits>
template <typename...>
using void_t = void;
template <typename T, typename = void>
struct has_bar
: std::false_type { };
template <typename T>
struct has_bar<T, void_t<decltype( std::declval<T&>().bar() ) > >
: std::true_type { };
class A {
public:
void foo() { };
};
class B {
public:
void bar() { };
};
class C {
public:
void bar() { };
};
template <typename T>
typename std::enable_if<!has_bar<T>::value, void>::type
fun(T t) {
std::cout << "fun" << std::endl;
}
template <typename T>
typename std::enable_if<has_bar<T>::value, void>::type
fun(T t) {
std::cout << "special fun" << std::endl;
}
The code...
int main(const int argc, const char* argv[argc]) {
A a;
B b;
C c;
fun(a);
fun(b);
fun(c);
return 0;
}
prints out
fun
special fun
special fun
Note, that does not check any type semantics, so it may be better declaring bar() as an interface and using std::is_base_of.
You should take a look on SFINAE to enable and disable function at compile time
If D and E are special, they have let's say the member void bar() and not the others, you can actually implement your own type trait:
template<typename T>
struct has_bar {
private:
template<typename C> static std::true_type test(decltype(&C::bar)*);
template<typename C> static std::false_type test(...);
public:
constexpr static bool value = decltype(test<T>(nullptr))::value;
};
/* false */ /* true */
cout << boolalpha << has_bar<A> << " " << has_bar<E> << endl;
Now with this type trait you can use std::enable_if as a compile time switch:
/* standard if no bar */
template<typename T, typename = enable_if_t< !has_bar<T> >>
void foo()
{
//standard implementation
}
/* special if bar */
template<<typename T, typename = enable_if_t< has_bar<T> >>
void foo()
{
//special implementation
}
AFAIK there's no way you can do this without defining some SFINAE machinery. Now the minimum I can think of without including type_traits header would be the following:
Define "home made "enable_if and is_same type traits as follows.
namespace mine {
template<bool, typename T = void> struct enable_if {};
template<typename T> struct enable_if<true, T> { typedef T type; };
template<typename T, typename U> struct is_same { static bool const value = false; };
template<typename T> struct is_same<T, T> { static bool const value = true; };
};
Apply SFINAE in member function foo() of class A as follows:
class A {
template<typename T>
struct pred {
static bool const value = mine::is_same<T, B>::value ||
mine::is_same<T, C>::value || mine::is_same<T, D>::value || mine::is_same<T, E>::value;
};
public:
template<typename T>
typename mine::enable_if< pred<T>::value, void>::type
foo() { std::cout << "special implementation" << std::endl; }
template<typename T>
typename mine::enable_if<!pred<T>::value, void>::type
foo() {std::cout << "standard implementation" << std::endl; }
};
LIVE DEMO
P.S the bonus is that the above solution works also for pre C++11 compilers.
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();
};
I want to make this specialized w/o changing main. Is it possible to specialize something based on its base class? I hope so.
-edit-
I'll have several classes that inherit from SomeTag. I don't want to write the same specialization for each of them.
class SomeTag {};
class InheritSomeTag : public SomeTag {};
template <class T, class Tag=T>
struct MyClass
{
};
template <class T>
struct MyClass<T, SomeTag>
{
typedef int isSpecialized;
};
int main()
{
MyClass<SomeTag>::isSpecialized test1; //ok
MyClass<InheritSomeTag>::isSpecialized test2; //how do i make this specialized w/o changing main()
return 0;
}
This article describes a neat trick: http://www.gotw.ca/publications/mxc++-item-4.htm
Here's the basic idea. You first need an IsDerivedFrom class (this provides runtime and compile-time checking):
template<typename D, typename B>
class IsDerivedFrom
{
class No { };
class Yes { No no[3]; };
static Yes Test( B* ); // not defined
static No Test( ... ); // not defined
static void Constraints(D* p) { B* pb = p; pb = p; }
public:
enum { Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };
IsDerivedFrom() { void(*p)(D*) = Constraints; }
};
Then your MyClass needs an implementation that's potentially specialized:
template<typename T, int>
class MyClassImpl
{
// general case: T is not derived from SomeTag
};
template<typename T>
class MyClassImpl<T, 1>
{
// T is derived from SomeTag
public:
typedef int isSpecialized;
};
and MyClass actually looks like:
template<typename T>
class MyClass: public MyClassImpl<T, IsDerivedFrom<T, SomeTag>::Is>
{
};
Then your main will be fine the way it is:
int main()
{
MyClass<SomeTag>::isSpecialized test1; //ok
MyClass<InheritSomeTag>::isSpecialized test2; //ok also
return 0;
}
And the short version now, 2014, using C++-11:
#include <type_traits>
struct SomeTag { };
struct InheritSomeTag : SomeTag { };
template<typename T, bool = std::is_base_of<SomeTag, T>::value>
struct MyClass { };
template<typename T>
struct MyClass<T, true> {
typedef int isSpecialized;
};
int main() {
MyClass<SomeTag>::isSpecialized test1; /* ok */
MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
}
Well, the article in the answer above appeared in February 2002. While it works, today we know there are better ways. Alternatively, you can use enable_if:
template<bool C, typename T = void>
struct enable_if {
typedef T type;
};
template<typename T>
struct enable_if<false, T> { };
template<typename, typename>
struct is_same {
static bool const value = false;
};
template<typename A>
struct is_same<A, A> {
static bool const value = true;
};
template<typename B, typename D>
struct is_base_of {
static D * create_d();
static char (& chk(B *))[1];
static char (& chk(...))[2];
static bool const value = sizeof chk(create_d()) == 1 &&
!is_same<B volatile const,
void volatile const>::value;
};
struct SomeTag { };
struct InheritSomeTag : SomeTag { };
template<typename T, typename = void>
struct MyClass { /* T not derived from SomeTag */ };
template<typename T>
struct MyClass<T, typename enable_if<is_base_of<SomeTag, T>::value>::type> {
typedef int isSpecialized;
};
int main() {
MyClass<SomeTag>::isSpecialized test1; /* ok */
MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
}
In your case, the only way that I see would be to explicitly specialize MyClass for InheritSomeTag. However, the SeqAn paper proposes a mechanism called “template sublassing” that does what you want – albeit with a different inheritance syntax, so the code isn't compatible with your current main function.
// Base class
template <typename TSpec = void>
class SomeTag { };
// Type tag, NOT part of the inheritance chain
template <typename TSpec = void>
struct InheritSomeTag { };
// Derived class, uses type tag
template <typename TSpec>
class SomeTag<InheritSomeTag<TSpec> > : public SomeTag<void> { };
template <class T, class Tag=T>
struct MyClass { };
template <class T, typename TSpec>
struct MyClass<T, SomeTag<TSpec> >
{
typedef int isSpecialized;
};
int main()
{
MyClass<SomeTag<> >::isSpecialized test1; //ok
MyClass<SomeTag<InheritSomeTag<> > >::isSpecialized test2; //ok
}
This certainly looks strange and is very cumbersome but it allows a true inheritance mechanism with polymorphic functions that is executed at compile time. If you want to see this in action, have a look at some SeqAn examples.
That being said, I believe that SeqAn is a special case and not many applications would profit from this extremely difficult syntax (deciphering SeqAn-related compiler errors is a real pain in the *ss!)
Using concepts and the requires keyword from C++20 is an even simpler and more expressive way to do this without having to introduce a redundant boolean non-type template parameter like in C++11:
// C++20:
#include <concepts>
#include <iostream>
struct SomeTag { };
struct InheritSomeTag : SomeTag { };
template<typename T>
struct MyClass
{
void Print()
{
std::cout << "Not derived from someTag\n";
}
};
// std::derived_from is a predefined concept already included in the STL
template<typename T>
requires std::derived_from<T, SomeTag>
struct MyClass<T>
{
void Print()
{
std::cout << "derived from someTag\n";
}
};
int main()
{
MyClass<InheritSomeTag> test1;
test1.Print(); // derived from someTag
MyClass<int> test2;
test2.Print(); // Not derived from someTag
// Note how even the base tag itself returns true from std::derived_from:
MyClass<SomeTag> test3;
test3.Print(); // derived from someTag
}