Specializing a class template by a base class - c++

I have distilled my doubt to this following piece of code
struct base {};
struct derived : public base {};
template <class T>
struct Type { };
template <> struct Type<base> {
typedef float mytype;
};
typename Type<base>::mytype a=4.2; // this works
typename Type<derived>::mytype a=4.2; // this doesnt
Could anyone explain why I cannot intantiate the class template object with derived and suggest a simple way to do it. For the actual problem that I am interested in there are many derived classes using which I want to intantiate template class objects and/or use typedefs. There are too many of them than what I would want to specialize individually.
EDIT: Forgot to mention, my bad, this needs to be C++03

#include <iostream>
#include <type_traits>
struct base { };
struct derived : base { };
template<typename T, bool = std::is_base_of<base, T>::value>
struct Type { };
template<typename T>
struct Type<T, true>
{
typedef float mytype;
};
int main()
{
Type<base>::mytype a1 = 4.2f;
Type<derived>::mytype a2 = 8.4f;
std::cout << a1 << '\n' << a2 << '\n';
}
In C++03, std can be trivially replaced with boost: boost::is_base_of

Two instantiations of a template class with different template arguments are totally unrelated class types. Type<derived> has no relation whatsoever to Type<base>, which of course means it doesn't use the specialisation and is instantiated from the primary template. The primary template has no nested type mytype.

Related

Simplify declarations of classes that use the CRTP pattern

I used the "Curiously Recurring Template Pattern" to inherit a static member variable and an instance getter. Sounds contrived, but the project will have many many subclasses that need to be declared as painlessly as possible, without duplicating the code.
I came up with the following, which works just fine:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
struct Base {
virtual void printStrings() = 0;
};
template <typename T>
struct static_strings: Base {
static std::vector<std::string> strings;
static void addString(const std::string& s) {
strings.push_back(s);
}
virtual void printStrings() {
for (auto s: T::strings) {
std::cout << s << std::endl;
}
}
};
template <typename T> std::vector<std::string> static_strings<T>::strings;
struct Sub1: static_strings<Sub1> {};
struct Sub2: static_strings<Sub2> {};
int main() {
Sub1::addString("test 1");
std::shared_ptr<Base> s1 = std::make_shared<Sub1>();
Sub2::addString("test 2");
std::shared_ptr<Base> s2 = std::make_shared<Sub2>();
std::cout << "s1: ";
s1->printStrings();
std::cout << "s2: ";
s2->printStrings();
return 0;
}
However, I'd like to further simplify the declaration of new subclasses, since right now I would have to copy the declaration and change the class name twice in the pasted line (struct Sub3: static_strings<Sub3> {};). I could use a macro, but I wonder if there's a non-macro (template?) way to do this?
You could easily change your Base tp take a pack of template template arguments to derive from:
template <typename T, template<typename> typename... OtherBases>
struct Base : OtherBases<T>... {
[...]
};
struct Sub1: Base<Sub1, static_strings> {};
struct Sub2: Base<Sub2, static_strings> {};
Not a big win here, but if you have more crtp base classes, that could help a bit. I can't imagine a way to save the remaining repetition without a macro, though.
Live code here.
For the shared_pointer thing, you'll need to derive from an additional non-templated base class.
struct AbstractBase {
virtual ~AbstractBase() = default;
virtual void printStrings() = 0;
};
template <typename T, template<typename> typename... OtherBases>
struct Base : AbstractBase, OtherBases<T>... {... };
Then you create shared pointers from that one:
std::shared_ptr<AbstractBase> s1 = std::make_shared<Sub1>();
std::shared_ptr<AbstractBase> s2 = std::make_shared<Sub2>();
See here for an updated example.
You can use a helper type:
struct helper : foo<helper>, bar<helper> {};
This alone won't do it, because all types inheriting from it would share the same base classes. To avoid repeating the type name you can introduce a dummy template parameter:
template <typename T>
struct foo {};
template <typename T>
struct bar{};
template <int x>
struct helper : foo<helper<x>>, bar<helper<x>> {};
using Sub1 = helper<1>;
using Sub2 = helper<2>;
int main () {
}
Thats what you can do without macros. With macros you can use __COUNTER__ (gcc has it, not sure about the others) to get distinct ints:
using SubA = helper<__COUNTER__>;
using SubB = helper<__COUNTER__>;

Interdependent class template and std::is_base_of specialization

I am mildy confused by the following situation where I have a specialization enabled on is_base_of.
is_base_of requires the full definition of the type that is being checked to be available. However, the type that is being specialized is being used as a member of the type who's base is being checked - so both need to be defined before the other, and I cannot forward declare the inheritance relationship.
What is confusing is that if I instead tag the base and enable on this tag existing, it works. Surely for this to work, the inheritance relationship must be known at this point. so why doesn't is_base_of work without the full definition being available?
#define OPTION 2 // OPTION 2 : broken, OPTION 1 : works
#include <iostream>
#include <type_traits>
using namespace std;
template <typename T,typename Enable=void>
struct child;
template <typename T>
struct base
{
typedef T type;
#if OPTION ==1
struct base_tag{};
#endif
};
#if OPTION ==2
template <typename T>
struct child < T, typename std::enable_if < std::is_base_of< base<typename T::type>, T>::value>::type>
{
const char* value = "specialization";
};
#else
template <typename T>
struct child < T, std::void_t<typename T::base_tag> >
{
const char* value = "specialization";
};
#endif
template <typename T>
struct dervived : base<T>
{
child<dervived> child_;
typedef T type;
};
int main() {
std::cout << dervived<int>().child_.value << std::endl;
return 0;
}
DEMO
std::is_base_of requires complete type. which is not the case in
template <typename T>
struct derived : base<T>
{
child<derived> child_; // derived<T> not yet complete here.
typedef T type;
};
For T::base_tag, IIRC (I think POI of child<derived> move from before struct derived to current location in the class), T doesn't need to be complete, and only visited part of it is visible.
So derived::type would not be visible. (but derived::base::type would be).

What would a CRTP-based solution to this look like?

I asked the following question in this post (pasted below for convenience). One of the comments suggested that there is a CRTP-based solution to the problem. I am not able to figure out how CRTP is relevant here (well, I never used CRTP before, so I am not used to thinking in these terms). So, how would a CRTP-based solution look like?
Here is the cited question:
Is it possible to write a template function that would possess type information about the base class of the template argument? (assuming that the template argument derives from one class only)
So, I am looking for something like this:
template <class T>
auto f(T t) -> decltype(...) { // ... is some SFINAE magic that
// catches B, the base of T
std::cout << (B)t << std::endl;
}
Some relevant background: I am writing a generic implementation of the A* algorithm. The template argument is a Node structure. So, the user might define:
struct NodeBase {
REFLECTABLE((double)g, (double)f)
// Using the REFLECTABLE macro as described here:
// https://stackoverflow.com/a/11744832/2725810
};
struct NodeData : public NodeBase {
using Base1 = NodeBase;
REFLECTABLE((double)F)
};
I would like to write a function that prints the contents of the node structure. REFLECTABLE does all the hard work of extracting the fields of the struct. However, when the user gives me a NodeData instance, my function needs to print the contents of the NodeBase component as well. I would like to later add overloads of my function for two and three base classes.
to know whether a class derives from a base class we have the std::is_base_of<> template structure, which can be used in conjunction with partial specialisation, or std::enable_if.
Here is a demonstration of using a partially specialised structure to apply a an operation depending on whether it's derived from node_base or not (in this case, it just prints the base object but you could do any other operation)
#include <iostream>
#include <type_traits>
// base class
struct node_base
{
};
std::ostream& operator<<(std::ostream& os, const node_base& nb)
{
os << "node_base_stuff";
return os;
}
// a class derived from node_base
struct node : public node_base
{
};
// a class not derived from node_base
struct not_node
{
};
// apply the general case - do nothing
template<class T, class = void>
struct report_impl
{
static void apply(const T&) {};
};
// apply the case where an object T is derived from node_base
template<class T>
struct report_impl<T, std::enable_if_t< std::is_base_of<node_base, T>::value > >
{
static void apply(const T& t) {
std::cout << static_cast<const node_base&>(t) << std::endl;
};
};
// the general form of the report function defers to the partially
// specialised application class
template<class T>
void report(const T& t)
{
report_impl<T>::apply(t);
}
using namespace std;
// a quick test
auto main() -> int
{
node n;
not_node nn;
report(n);
report(nn);
return 0;
}
expected output:
node_base_stuff
Here is my own first solution. It is not CRTP though and it suffers from a huge drawback as explained at the end of the answer:
template <class Base1_ = void, class Base2_ = void, class Base3_ = void,
class Base4_ = void>
struct ManagedNode;
// For classes that do not derive
template <> struct ManagedNode<void, void, void, void> {
using Base1 = void; using Base2 = void; using Base3 = void;
using Base4 = void;
};
// To avoid inaccessible base
// See http://stackoverflow.com/q/34255802/2725810
struct Inter0: public ManagedNode<>{};
// For classes that derive from a single base class
template <class Base1_>
struct ManagedNode<Base1_, void, void, void> : public Inter0,
public Base1_ {
using Base1 = Base1_;
};
// To avoid inaccessible base
template <class Base1_>
struct Inter1: public ManagedNode<Base1_>{};
// For classes that derive from two base classes
template <class Base1_, class Base2_>
struct ManagedNode<Base1_, Base2_, void, void> : public Inter1<Base1_>,
public Base2_ {
using Base2 = Base2_;
};
// Some user classes for testing the concept
struct A : public ManagedNode<> {
int data1;
};
struct B : public ManagedNode<> {};
struct C : public ManagedNode<A, B> {};
int main() {
C c;
std::cout << sizeof(c) << std::endl;
return 0;
}
This code produces the output of 12, which means that c contains the data1 member three times! For my purposes this drawback over-weighs the benefits of the reflection that this approach provides. So, does anyone have a suggestion for a better approach?

Is it possible to check at compile time whether a type is derived from some instantiation of a template?

I would like to write a template function which behaves one way if the passed type is derived from any template instantiation of another class, and another way if not.
I think the code below captures what I would like to do. Unfortunately Caller prints "generic" for both double and Derived.
#include <iostream>
template <typename T>
struct Base
{
};
struct Derived
:
public Base<int>
{
};
template <typename T>
void Foo(const T&)
{
std::cout << "generic" << std::endl;
}
template <typename T>
void Foo(const Base<T>&)
{
std::cout << "derives from Base<T>" << std::endl;
}
template <typename T>
void Caller(const T& t)
{
Foo(t);
}
int main()
{
double x;
Caller(x);
Derived d;
Caller(d);
return 0;
}
(Note that Caller doesn't know which instantiation of Base that its parameter might derive from.)
It's calling the const T& overload because its a better match than const base<T>&. The reason is because calling the first requires no conversions and the second requires a derived-to-base conversion.
Here's a quick hack that shows you how it can be done (note the introduced base class):
#include <iostream>
#include <type_traits>
struct EvenMoreBase {};
template <typename T>
struct Base : EvenMoreBase
{
};
struct Derived
:
public Base<int>
{
};
template <typename T>
typename std::enable_if<!std::is_base_of<EvenMoreBase, T>::value>::type
Foo(const T&)
{
std::cout << "generic" << std::endl;
}
template <typename T>
void Foo(const Base<T>&)
{
std::cout << "derives from Base<T>" << std::endl;
}
template <typename T>
void Caller(const T& t)
{
Foo(t);
}
int main()
{
double x;
Caller(x);
Derived d;
Caller(d);
return 0;
}
If you're able to use C++11 (or <type_traits> in general), the following is also a possible solution and covers not only types T : Base<T>, i.e. instances of the CRTP, but also T : Base<U> without another base class, as requested in your example.
#include <iostream>
#include <type_traits>
template <typename T>
struct Base
{
typedef T base_value_type;
};
struct Derived : public Base<int>
{
};
template <typename T, typename = T>
struct IsDerived
{
static const bool value = false;
};
template <typename T>
struct IsDerived<T, typename std::enable_if<std::is_base_of<Base<typename T::base_value_type>, T>::value, T>::type>
{
static const bool value = true;
};
template <typename T>
void Caller(const T&)
{
std::cout << IsDerived<T>::value << std::endl;
}
int main()
{
Caller(double()); // false
Caller(Derived()); // true
return 0;
}
Note the typedef T base_value_type - which might be called whatever your like. The idea is that each type T derived from Base<U> can leverage the knowledge of the base's template parameter. It doesn't matter if T == U or not. Trying to substitute the second parameter will fail as soon as you pass in a T that has no typedef T base_value_type and thus no specialization for this particular T will be generated.
EDIT: After processing your comment, and inspired by the thread I posted, I tried to somehow extract some base parameter U when examining some time type T : Base<U>. I don't think this can be done in the way you want, i.e. you pass whatever T and you extract U. However, you can do two things.
Simple Solution: If you have control over how derived classes are implemented, instead of adding a typedef in the base class, simply add a corresponding typedef in the derived class:
template <typename BaseParamType>
class Derived : public Base<BaseParamType>
{
public:
typedef BaseParamType base_param_type;
}
or, if you don't want derived classes to be class templates as well, simply hard code the type right into the type (you already know the type of the base parameter):
class Derived : public Base<int>
{
public:
typedef int base_param_type;
}
More involved solution: What you can do, at least for an expected subset of possible Us, is the following:
template <typename DerivedType,
typename BaseParamType = DerivedType,
bool = std::is_base_of<Base<BaseParamType>, DerivedType>::value>
struct Extract
{
typedef BaseParamType type;
};
template <typename T, typename U>
struct Extract<T, U, false>;
int main()
{
Extract<DerivedCRTP>::type; // CRTP - trivial
Extract<Derived, int>::type; // type == int, Derived is derived from Base<int>
Extract<Derived, double>::type; // compile-time error, undefined template
return 0;
}
This isn't as convenient as passing some instance of a type to a deducing template function and have it magically , but you can at least test if some type T derives from Base<U> and get a compile-time error if it doesn't.
Since the base class has to be a concrete class (not a template), it is not possible to know whether it is a template or a non-template class.
In another words :
struct A1 : public B1
{};
struct A2 : public B2<int>
{};
in both of these cases both base classes are concrete types.

Simplest way to provide template specialization for derived classes

I have the following scenario:
class my_base { ... }
class my_derived : public my_base { ... };
template<typename X>
struct my_traits;
I want to specialize my_traits for all classes derived from my_base including, e.g.:
template<typename Y> // Y is derived form my_base.
struct my_traits { ... };
I have no problems with adding tags, members to my_base to make it simpler. I've seen some tricks but I still feel lost.
How can this be done in a simple and short way?
Well, you don't need to write your own isbaseof. You can use boost's or c++0x's.
#include <boost/utility/enable_if.hpp>
struct base {};
struct derived : base {};
template < typename T, typename Enable = void >
struct traits;
template < typename T >
struct traits< T, typename boost::enable_if<std::is_base_of<base, T>>::type >
{
enum { value = 5 };
};
#include <iostream>
int main()
{
std::cout << traits<derived>::value << std::endl;
std::cin.get();
}
There are scaling issues but I don't believe they're any better or worse than the alternative in the other question.