Is there a way to detect whether a class is a template class or a simple class at compile time?
Eg:
class A
{
public:
void GetValue()
{
return 10 (compile time check? "": "+ 10"); // just an example
}
};
class B : public A
{
};
template <class T>
class C : public A
{
};
You may create a traits for that:
template <typename T>
struct is_type_templated : std::false_type {};
template <template <typename...> class C, typename ... Ts>
struct is_type_templated<C<Ts...>> : std::true_type {};
Live example
Note that it doesn't handle templated value (as std::array<T, N>).
Related
I am still working on this problem I posted some hours before:
[How to overload/specialize template class function to handle arithmetic types and a container-class
I tried to implement this solution. It compiles but the object is created with the DerivedClass-Constructor instead of the partial specialized template class DerivedClass< Eigen::ArrayBase >
Do you have an Idea where I made a (or some) misstakes?
template <typename T> class BaseClass
{
protected:
T mem;
public:
BaseClass(T arg) : mem(arg){};
};
template <typename T> class DerivedClass : public BaseClass<T>
{
public:
DerivedClass(T arg): BaseClass<T>(arg){};
};
template <typename T>
class DerivedClass<Eigen::ArrayBase<T> >
: public DerivedClass<Eigen::ArrayBase<T> >
{
public:
DerivedClass(Eigen::ArrayBase<T> arg):BaseClass<Eigen::ArrayBase<T> >(arg){};
};
int main
{
...
Eigen::Array3d arg = Array3d::Random(3);
DerivedClass<Eigen::Array3d> o(arg);
....
}
template<template<class...>class Z>
struct template_instance_test {
static std::false_type test(...);
template<class...Ts>
static std::true_type test( Z<Ts...> const* );
template<class X>
using tester = decltype(test( std::declval<X*>() ) );
};
template<template<class...>class Z, class T>
using is_derived_from_template = typename template_instance_test<Z>::template tester<T>;
we can now ask if something is an instance of a particular template, or derived from an instance of a particular template.
template<class X>
struct Base {};
template<class X>
struct Derived:Base<X> {};
template<class T>
struct Storage {
T data;
};
template<class T, class=void>
struct Instance:Storage<T> {
enum {is_special = false};
};
template<class T>
struct Instance<T, std::enable_if_t< is_derived_from_template<Base, T>{} > >:
Storage<T> {
enum { is_special = true };
};
int main() {
Instance<int> i; (void)i;
static_assert(!Instance<int>::is_special);
Instance<Derived<int>> j; (void)j;
static_assert(is_derived_from_template<Base, Base<int>>{});
static_assert(is_derived_from_template<Base, Derived<int>>{});
static_assert(Instance<Derived<int>>::is_special);
}
and we are done. Live example.
Your code should works if Eigen::Array3d is an alias (through using or typedef) of Eigen::ArrayBase<T> for some T.
But I suppose that Eigen::Array3d inherit from Eigen::ArrayBase<T>. So isn't a ``Eigen::ArrayBase`, so doesn't matches the partial specialization, so matches the main template.
If you want a specialization that intercept all classes derived from Eigen::ArrayBase, a possible solution is add an additional template parameter with a default value and activate the specialization only it T derive from some Eigen::ArrayBase.
Something as follows (caution: code not tested)
constexpr std::false_type isArray (...);
template <typename T>
constexpr std::true_type isArray (Eigen::ArrayBase<T> const *);
template <typename T, typename = std::true_type>
class DerivedClass : public BaseClass<T>
{
public:
DerivedClass(T arg): BaseClass<T>(arg){};
};
template <typename T>
class DerivedClass<T, decltype(isArray(std::declval<T*>())>
: public DerivedClass<T>
{
public:
DerivedClass (T arg) : BaseClass<T>(arg){};
};
I want to write a concept that tests for inheritance from a base class.
My Base class is publicly inherited by Derived classes, using CRTP.
This code works fine:
#include <type_traits>
namespace NS
{
template<typename D>
class Base {
// ...
};
class Derived : public Base<Derived>
{
public:
constexpr Derived() = default;
// ...
};
}
template<typename D>
concept bool inheritsFromB() {
return std::is_base_of<NS::Base<D>, D>::value;
}
template<inheritsFromB b>
void myFunct() {};
int main() {
constexpr auto d = NS::Derived();
using dType = typename std::decay<decltype(d)>::type;
myFunct<dType>();
}
I hit a problem if I want to template Derived. Is this possible?
namespace NS
{
template<typename D, typename T>
class Base { ... };
template<typename T>
class Derived : public Base<Derived<T>, T>
{ // ...
// probably some using declaration for T?
};
}
template<template <typename> class D>
concept bool inheritsFromB() {
return std::is_base_of<NS::B<D<T>,T>, D<T>::value;
}
...
the obvious problem being that I have no T in my concept declaration.
Moreover, I'm pretty sure I can't declare
template<template <typename> class D, typename T>
concept bool inheritsFromB() {
...
}
because a concept requires one template parameter.
Edit - the Working Paper P0121R0 lists in section 8.3.5, p23, template<typename T, typename U> concept bool C3 = true;. Consequently, wherever I read a concept can take only one parameter was either outdated, wrong, or I read it lacking care. end edit
Can I access the other type(s) T that I need here? Is there an alternative way (it seems to me like the template type D would carry the information of what it's type T is, but I also can't use using T = typename D<T>::valueType;, because I need the T to specific the type of D<T>...)
I suspect the following trait should work:
#include <type_traits>
#include <utility>
namespace NS
{
template <typename D, typename T>
class Base {};
template <typename T>
class Derived : public Base<Derived<T>, T> {};
}
namespace detail
{
template <typename T, template <typename> typename D>
std::true_type is_derived_from_base(const ::NS::Base<D<T>,T>*);
std::false_type is_derived_from_base(void*);
}
template <typename T>
using is_derived_from_base = decltype(detail::is_derived_from_base(std::declval<T*>()));
template <typename T>
concept bool inheritsFromB()
{
return is_derived_from_base<T>{};
}
DEMO (without concepts)
Is it possible to generate a linear hierarchy from variadic template parameters? For example:
GenLinearHierarchy<A,B,C,D,...> linHierarchy;
Generates a hierarchy where A -> B -> C -> D -> ... -> Empty (where the -> symbol stands for inherits from).
Where the template parameters (template template... parameters) have signatures such as:
template <class Base, class Plate> class A;
Where Base is the class above A in the hierarchy and Plate is the 'most derived' class (for example D< E<...>, A<...> >).
So far I've been unsuccessful - starting to wonder whether I'm going in circles (I do keep running into cyclic problems).
Sorry about the confusion - here is a 'concrete solution' (one which I'm not too fond of):
// Linear Hierarchy
#include <iostream>
template <class Base, class Floor>
class D : public Base
{
public:
};
template <class Base, class Floor>
class C : public Base
{
public:
void Fire()
{
static_cast<Floor*>(this)->Handle();
}
};
template <class Base, class Floor>
class B : public Base
{
public:
void Handle()
{
std::cout << "Handled" << std::endl;
}
};
class _FINISH {};
class _START : public B<C<D<_FINISH, _START>, _START, _START> {};
int main()
{
typedef _START A;
A a;
a.Fire();
return 0;
}
So, I'm still looking for a 'GenLinearHierarchy' class which can generate something like above, but with an instatiation like this:
GenLinearHierarchy<B,C,D> linHierarchy;
Thanks :)
I don't think you can let Plate be the most derived type, as that would mean the overall type would have to have itself as one of its own template parameters. This is the closest I've gotten:
struct Empty {};
template <template <class> class Head, template <class> class... Tail>
struct GenLinearHierarchy
{
typedef Head<typename GenLinearHierarchy<Tail...>::type> type;
};
template <template <class> class Tail>
struct GenLinearHierarchy<Tail>
{
typedef Tail<Empty> type;
};
template <class Base> struct A : Base {};
template <class Base> struct B : Base {};
template <class Base> struct C : Base {};
template <class Base> struct D : Base {};
static_assert(std::is_same< typename GenLinearHierarchy<A,B,C,D>::type
, A<B<C<D<Empty>>>> >::value
, "");
EDIT I think I've got what you wished for. Good luck trying to read it. You've only got yourself to blame. :)
struct Empty {};
template <class MostDerived,
template <class, class> class Head,
template <class, class> class... Tail>
struct GenLinearHierarchyInner
{
typedef Head<typename GenLinearHierarchyInner<MostDerived,
Tail...>::type,
MostDerived> type;
};
template <class MostDerived,
template <class, class> class Tail>
struct GenLinearHierarchyInner<MostDerived, Tail>
{
typedef Tail<Empty, MostDerived> type;
};
template <template <class, class> class... Types>
struct GenLinearHierarchy : GenLinearHierarchyInner<GenLinearHierarchy<Types...>,
Types...>::type
{};
template <class Base, class> struct A : Base {};
template <class Base, class> struct B : Base {};
template <class Base, class> struct C : Base {};
template <class Base, class> struct D : Base {};
typedef GenLinearHierarchy<A,B,C,D> ABCD;
static_assert(std::is_base_of< A<B<C<D<Empty, ABCD>, ABCD>, ABCD>, ABCD>
, ABCD >::value
, "");
It's probably something like this...
template<typename T, typename... Args>
class GenLinearHierarchy : public T, public GenLinearHierarchy<Args...> {};
template<typename T>
class GenLinearHierarchy<T> : public T {};
I wrote the following:
//Policy Classes
template
<typename T>
struct CheckForZeroSpeed
{
};
template
<typename T>
struct NoCheck
{
};
//Specialization for one of the Policy Classes
template
<>
struct NoCheck<float>
{
};
//Class that uses Policy
template
<typename T,template <class C> class Policy>
class Base : public Policy<T>
{
};
//Inherited class that uses Policy
template
<typename T,template <class C> class Policy>
class Derived : public Base<T,Policy>
{
};
How can I declare a specialization of the Base class (let's say for the int type) and a specialization for the Derived class?
This also works:
template
<>
class Base<int,NoCheck>
{
};
But this is a specialization based both on the type and the policy, is it a way to have specialization based only one (type) of the two template parameters? Something like:
//not compile
template
<template <class C> class Policy>
class Base<int,Policy<T>>
{
};
Edit:
The correct is:
//Partial specialization based on the type
template
<template <class C> class Policy>
class Base<int,Policy>
{
};
//Partial specialization based on the Policy
template
<typename T>
class Base<T,NoCheck>
{
};
Consider the following:
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//How do we typedef of redefine Base<T>::Nested?
using Base<T>::Nested; //This does not work
using Base<T>::template<typename U> Nested; //Cannot do this either
typedef typename Base<T>::template<typename U> Nested Nested; //Nope..
//now we want to use the Nested class here
template <typename U>
Class NestedDerived : public Nested { };
//or like this:
Nested<int> nestedVar; // obviously does not work
};
How to use the templated Nested class in the Derived class? Is this possible to do in current version of C++ standard?
Actually using works as advertised, it just doesn't get rid of the dependent-name issue in the template and it can't currently alias templates directly (will be fixed in C++0x):
template <class T>
struct Base {
template <class U> struct Nested {};
};
template <class T>
struct Derived : Base<T> {
using Base<T>::Nested;
// need to prefix Nested with template because
// it is a dependent template:
struct X : Base<T>::template Nested<int> {};
// same here:
template<class U>
struct Y : Base<T>::template Nested<U> {};
// data member, typename is needed here:
typename Base<T>::template Nested<int> data;
};
void f() {
Derived<int>::Nested<int> n; // works fine outside
}
There is another possible gotcha when using Derived<T>::Nested in templates, but again that is a dependent-name issue, not inheritance-related:
template<class T>
void g() {
// Nested is a dependent type and a dependent template, thus
// we need 'typename' and 'template':
typedef typename Derived<T>::template Nested<int> NestedInt;
}
Just remember that names that depend on template arguments have to be
prefixed with typename if its a dependent type: typename A<T>::B
directly prefixed with template if its a dependent template: A<T>::template f<int>()
both if both: typename A<T>::template B<int>
typename is illegal in base-class-lists: template<class T> struct A : B<T>, C<T>::template D<int> {};
This seems to work:
(EDIT: added some more lines to show the first template statement. And thanks to Samir Talwar for correcting my formatting!)
template <typename T, typename U>
class Derived : public Base<T> {
public:
typedef typename Base<T>::template Nested<U> Nested;
class NestedDerived : public Nested { };
Nested nestedVar;
};
Try this:
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//How do we typedef of redefine Base<T>::Nested?
//using Base<T>::Nested; //This does not work
//using Base<T>::template<typename U> Nested; //Cannot do this either
//typedef typename Base<T>::template<typename U> Nested Nested; //Nope..
//now we want to use the Nested class here
template <typename U>
class NestedDerived : public Base<T>::template Nested<U> { };
};
int main()
{
Base<int>::Nested<double> nested;
Derived<int>::NestedDerived<double> nested_derived;
return 0;
}
Compiled fine using gcc 4.3.3 on slackware 13
I'm still not 100% sure what you want, but you could try.
This compiled on Visual Studio
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//now we want to use the Nested class here
template <typename U>
class NestedDerived : public Nested<U> { };
};
int _tmain(int argc, _TCHAR* argv[])
{
Base<int>::Nested<double> blah2;
Derived<int>::NestedDerived<int> blah;
return 0;
}