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
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__>;
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).
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?
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.
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.