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)
Related
Consider the code below:
template <typename T>
class A{
...
}
template <class U>
class B{
...
}
int main {
B<A<int>> a;
...
}
How can I get the template parameter of A (int in this case) inside B, if A<int> is the template parameter for B?
I could parametrize B as follows, but I feel like I am sending an unnecessary piece of information.
template <class AA, typename T>
class B { ... }
The reason I do not simply use template <typename T> for class B is that I have a pointer to class A inside B, and I want to use the template parameter class AA to see if that pointer is const or not, hence have the correct type for the member pointer in B.
There are several ways, depending of that you might change:
Quick way, specialize B
template <class> class B;
template <class T>
class B<A<T>>
{
// Use directly T
//...
};
Add info in A directly (as std containers do with value_type)
template <typename T>
struct A
{
using my_type = T;
};
// Then in `B<U>`, use `typename U::my_type`
Use external traits to extract information from A (as std::iterator_traits) (that also allows to handle built-in types):
template <typename T>
struct ATrait;
template <typename T>
struct ATrait<A<T>>
{
using my_type = T;
};
// Possibly a generic one
template <template <typename> class C, typename T>
struct ATrait<C<T>>
{
using my_type = T;
};
// Then in `B<U>`, use `typename ATrait<U>::my_type`
I think the following does what you want:
#include<type_traits>
template<class>
class A{};
template<class>
struct get_inner;
template<template<class> class TT, class T>
struct get_inner<TT<T>> {
using outer = TT<T>;
using inner = T;
};
template<class TT>
struct B {
using A = TT;
using inner = typename get_inner<std::decay_t<A>>::inner;
};
int main(int argc, char *argv[])
{
static_assert(std::is_const_v<typename B<const A<int>>::A>);
static_assert(!std::is_const_v<typename B<A<int>>::A>);
}
Note the std::decay_t, it wouldn't work with the const parameter directly (hence we cannot just specialize B in this way). Maybe decay_t is a bit strong but it works^^
Try this
template <typename X> class B;
template <template <typename> class XX, typename T>
class B<XX<T>>
{
// your implementation
};
B<A<int>> a;
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){};
};
Something is not working quite well for me. Is this the way to declare a class, that accepts only floating point template parameter?
template <typename T, swift::enable_if<std::is_floating_point<T>::value> = nullptr>
class my_float;
I fail to define methods outside this class. Doesn't compile, not sure why
Well... not exactly SFINAE... but maybe, using template specialization? Something as follows ?
template <typename T, bool = std::is_floating_point<T>::value>
class my_float;
template <typename T>
class my_float<T, true>
{
// ...
};
If you really want use SFINAE, you can write
template <typename T,
typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
class my_float
{
// ...
};
or also (observe the pointer there isn't in your example)
template <typename T,
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
class my_float // ------------------------------------------------^
{
};
-- EDIT --
As suggested by Yakk (thanks!), you can mix SFINAE and template specialization to develop different version of your class for different groups of types.
By example, the following my_class
template <typename T, typename = void>
class my_class;
template <typename T>
class my_class<T,
typename std::enable_if<std::is_floating_point<T>::value>::type>
{
// ...
};
template <typename T>
class my_class<T,
typename std::enable_if<std::is_integral<T>::value>::type>
{
// ...
};
is developed for in two versions (two different partial specializations), the first one for floating point types, the second one for integral types. And can be easily extended.
You can also use static_assert to poison invalid types.
template <typename T>
class my_float {
static_assert(std::is_floating_point<T>::value,
"T is not a floating point type");
// . . .
};
It's a little bit more direct, in my opinion.
With either of the other approaches, e.g.
template <typename T, bool = std::is_floating_point<T>::value>
class my_float;
template <typename T> class my_float<T, true> { /* . . . */ };
my_float<int,true> is a valid type. I'm not saying that that's a bad approach, but if you want to avoid this, you'll have to encapsulate
my_float<typename,bool> within another template, to avoid exposing the bool template parameter.
indeed, something like this worked for me (thanks to SU3's answer).
template<typename T, bool B = false>
struct enable_if {};
template<typename T>
struct enable_if<T, true> {
static const bool value = true;
};
template<typename T, bool b = enable_if<T,is_allowed<T>::value>::value >
class Timer{ void start(); };
template<typename T, bool b>
void Timer<T,b>::start()
{ \* *** \*}
I am posting this answer because I did not want to use partial specialization, but only define the behavior of the class outside.
a complete workable example:
typedef std::integral_constant<bool, true> true_type;
typedef std::integral_constant<bool, false> false_type;
struct Time_unit {
};
struct time_unit_seconds : public Time_unit {
using type = std::chrono::seconds;
};
struct time_unit_micro : public Time_unit {
using type = std::chrono::microseconds;
};
template<typename T, bool B = false>
struct enable_if {
};
template<typename T>
struct enable_if<T, true> {
const static bool value = true;
};
template<typename T,
bool b = enable_if<T,
std::is_base_of<Time_unit,
T>::value
>::value>
struct Timer {
int start();
};
template<typename T, bool b>
int Timer<T, b>::start() { return 1; }
int main() {
Timer<time_unit_seconds> t;
Timer<time_unit_micro> t2;
// Timer<double> t3; does not work !
return 0;
}
Please consider the following code snippet:
template<class A, class B>
class c {};
template<class D>
class e
: public c<e<D>, /* some type depending on D */>
{ }
Given a type F, how can I check whether there is some type B such that F is derived from c<F, B>?
Example: For F = e<D> there is some type B depending on D such that F is derived from c<F, B>.
This answer focuses on the question;
Given a type F, how can I check whether there is some type B such that F is derived from c<F, B>?
And the comment for clarity;
The trait should check if F is derived from c<F, B> for some B (and it's not important what B is).
Two constexpr functions can be used to "attract" and differentiate the base c<F, B> away from other types. Function templates are favoured because they are able to deduce types (this would be required to satisfy the requirement some B). Something of the form as follows...
template <typename F, typename B>
constexpr bool check_base(C<F, B> &&) { return true; }
template <typename F>
constexpr bool check_base(...) { return false; }
The following sample, with improved usage scenarios, illustrates the basic workings;
#include <utility>
template <typename A, typename B>
struct C {};
template <typename F, typename B>
constexpr std::true_type check_base_(C<F, B>&&) { return {}; }
template <typename F>
constexpr std::false_type check_base_(...) { return {}; }
template <typename T>
using check_base = decltype(check_base_<T>(std::declval<T>()));
template <typename D>
struct E : C<E<D>, D> {};
struct FailF {};
int main()
{
static_assert(check_base<E<int>>());
static_assert(!check_base<FailF>());
}
See the demo here.
If we remove the constexpr, we can also remove the unneeded inline definitions of the check_base_ functions.
Note: the solutions assumes/asserts an accessible base class (i.e. not private or protected). If the base class is private, the code above would fail to compile, with an accessibility error. The code below will not fail, the SFINAE is done to allow the compilation to continue.
Online demo here.
#include <utility>
#include <type_traits>
template <typename A, typename B>
struct C {};
template <typename F, typename B>
std::true_type check_base_(C<F, B>&&, typename std::enable_if<std::is_convertible<F, C<F,B>>::value>::type* = nullptr);
template <typename F>
std::false_type check_base_(...);
template <typename T>
using check_base = decltype(check_base_<T>(std::declval<T>()));
template <typename D>
struct Example : C<Example<D>, D> {};
struct CtorTest : C<CtorTest, int> { CtorTest(int, int) {} };
struct PrivateBase : private C<PrivateBase, double> {};
struct FailTest {};
int main()
{
static_assert(check_base<Example<int>>(), "fail...");
static_assert(check_base<CtorTest>::value, "fail...");
static_assert(!check_base<PrivateBase>(), "fail...");
static_assert(!check_base<FailTest>(), "fail...");
}
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;
}