Access templated "using" in templated parent class - c++

I have a class hierarchy like this:
/* Base templated interface class */
template <class T>
class InterfaceClass {
public:
// Normal using sentence
using InnerType1 = SomeClass<T>;
// HERE1: Templated using sentence that I want to use in other places
template<typename SomeType>
using TplInnerType = SomeOtherClass<InnerType1, SomeType>;
};
/* Some templated intermediate class inheriting from the interface */
template <typename T>
class Class : InterfaceClass<T> {
public:
using BaseType = InterfaceClass<T>;
// This works
using typename BaseType::InnerType1;
// HERE2: This won't work in any form
using typename BaseType::TplInnerType;
};
/* Then I have some children using the CRTP as: */
class Child1 : Class<Child1> { ... };
class Child2 : Class<Child2> { ... };
I would like to use the templated using sentence (HERE1) from InterfaceClass in descendants (HERE2), but I cannot get the compiler (C++11 over clang 10) to resolve the type.
I have tried many combinations following compiler advice, including:
template <typename U> using typename BaseType::TplInnerType<U>;
template <typename U> using TplInnerType = BaseType::TplInnerType<U>;
template <typename U> using TplInnerType = typename BaseType::TplInnerType<U>;
template <typename U> using TplInnerType = BaseType::template TplInnerType<U>;
But suggestions drive my in a circle... Is what I try to do even possible?
Edit - another solution
Apart from #Jarod42 answer, which works for this toy example but not in my real case, I found another solution that works (sample):
template <typename T>
class Class : InterfaceClass<T> {
public:
using BaseType = InterfaceClass<T>;
using typename BaseType::InnerType1;
// This works
template <typename U>
using TplInnerType = typename BaseType::template TplInnerType<U>;
};

You should drop typename:
template <typename T>
class Class : public InterfaceClass<T> {
public:
using BaseType = InterfaceClass<T>;
using typename BaseType::InnerType1;
using BaseType::TplInnerType;
};
Demo

Related

Remove redundant template types

I am currently struggling with templates: I have a templated class A, which performs basic math (for floats, doubles, complex numbers) and looks like this
template <typename T>
class A
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Now I can use the class like A<double>, A<float>, but I would also like to use it like A<std::complex<float>> and A<std::complex<double>>. When using the latter, I would like the definition of foo to look like
void foo(std::vector<std::complex<float>>& result);
and not like
void foo(std::vector<std::complex<std::complex<float>>>& result);
Is there any way to create a specific template for the std::complex<T> cases, in which I can access the "inner" type? Or this is not possible/bad practice?
What is the most elegant way to solve this issue?
Another way can pass through the creation of a type traits to detect the (extract, when needed) the float type
template <typename T>
struct getFloatType
{ using type = T; };
template <typename T>
struct getFloatType<std::complex<T>>
{ using type = T; };
and use it in A (see fT)
template <typename T>
class A
{
public:
using fT = typename getFloatType<T>::type;
void foo(std::vector<std::complex<fT>>& result)
{ }
};
You can make a partial specialization for any instantiation of std::complex, e.g.
template <typename T>
class A<std::complex<T>>
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Then for A<std::complex<double>>, the signature of foo would be void foo(std::vector<std::complex<double>>& result);.
To handle those duplicated codes, you can make a base class and move the common members into it, and make the primary template and partial specialization both derive from it. e.g.
class Base {
public:
void bar(...);
};
then
template <typename T>
class A : public Base {
...
};
template <typename T>
class A<std::complex<T>> : public Base {
...
};

Use a template template parameter with CRTP in a Concept

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)

Template dependent typedefs

I am modifying a templated A* search and now have the following class (part of):
template <typename TNode, typename THeuristic>
class AStar
{
public:
// Typedefs.
typedef d_ary_heap<TNode*, boost::heap::compare<NodeCompare<TNode>>, boost::heap::arity<4>, boost::heap::mutable_<true>> PriorityQueueType;
//...
}
Until now, I hadn't thought of templatizing the heuristic parameter, so the Node class was defined as follows:
template <typename T = float>
class Node
{
public:
// Typedefs:
typedef typename AStar<Node>::PriorityQueueType::handle_type HeapHandle;
//...
}
But now since AStar takes a second template paremeter for the heuristic the typedef gives a compile error here: typedef typename AStar<Node ??>.... Is it possible to make this work somehow while maintaining freedom to specify the heuristic in the AStar class?
You could factor your code differently and keep the heuristic-independent part separate:
namespace detail
{
template <typename T>
struct AStarHeap
{
using QueueType = /* ... */;
using HandleType = QueueType::handle_type;
// ...
};
}
template <typename Node, typename Heur>
struct AStar : detail::AStarHeap<Node>
{
// ...
};
template <typename T>
struct Node
{
using HeapHandle = typename detail::AStarHeap<T>::HandleType;
// ...
};
Reworking a bit from my comment on the question, here's how I would probably do it:
template <typename TNode, typename THeuristic = void>
class AStar;
template <typename TNode>
class AStar<TNode>
{
// put everything that does not depend on THeuristic here
};
template <typename TNode, typename THeuristic>
class AStar : public AStar<TNode>
{
// put everything that does depend on THeuristic here
};
Looking at it now, this takes much the same approach as Kerrek SB's answer, but has the advantage that your existing code, which uses AStar<TNode>, continues to compile so long as it does not attempt to do anything that requires THeuristic.

typedef template without template rebind. Use as a template of template class parameter

I want to do something like this:
template<class T>
class BaseSubscriber {};
template<class T>
class BasePublisher
{
// not working : invalid use of template-name 'BaseSubscriber' without an argument list
typedef BaseSubscriber SubscriberType;
// compiling
typedef BaseSubscriber<T> SubscriberTypeT;
};
template< template<class T> class Subscriber, class Data >
class ClassA:
public Subscriber<Data>
{
};
template< template<class T> class Publisher, class Data >
class ClassB:
public Publisher<Data>
{
// Ok, but I want that the type "BaseSubscriber" depends on the template parameter Publisher
void method1(ClassA<BaseSubscriber, Data>&);
// I want something like that. But how to define SubscriberType ?
void method2(ClassA<Publisher<Data>::SubscriberType, Data>&);
// or (SubscriberType only depends on the Publisher, nor on the Data)
void method2(ClassA<Publisher::SubscriberType, Data>&);
// Error : template argument is invalid
void method3(ClassA<Publisher::SubscriberTypeT, Data>&);
};
Is it possible to define some SubscriberType that I can use for classA template parameter? Or is there any work around?
If possible I'd like to keep the classA prototype. I don't want to change it in
template<class TSubscriber > classA {};
And I can't use C++11.
Thanks a lot for your answers.
It is a bit confusing what you mean when you say:
// I want something like that. But how to define SubscriberType ?
void method2(ClassA<Publisher::SubscriberType>);
As Publisher is a template yet you're not passing it any arguments.
Anyway, here are some options:
In C++11 you can use template aliases:
template<class T>
class BasePublisher
{
template<typename U>
using SubscriberType = BaseSubscriber<U>;
};
You can also use nested classes:
template<class T>
class BaseSubscriber {};
template<class T>
class BasePublisher
{
template<class U>
class BaseSubscriber {};
};
Or change ClassA to use a type member:
template<class T>
class BasePublisher
{
template<class U>
struct SubscriberType {
typedef BaseSubscriber<U> type;
};
};
template< template<class T> class SubscriberT >
class ClassA {
typedef typename SubscriberT::type Subscriber;
};
Or sometimes inheritance works if you don't need an alias:
template<class T>
class BasePublisher
{
template<class U>
struct SubscriberType : BaseSubscriber<U> {};
};
Template aliases are not allowed in C++03 although they are in C++11.
Is your goal is to be able to do:
typename BaseSubscriber<A>::SubscriberType<B>
in C++03 you should use a nested class thus:
template< typename T > struct BasePublisher
{
template< typename U > struct Subscriber
{
typedef BaseSubcriber<U> type;
};
};
and now you can possibly do typename BasePublisher::Subscriber::type;
In C++11 the syntax would be:
template < typename T > struct BasePublisher
{
template< typename U > using SubscriberType = BaseSubscriber<U>;
};
there are not many compilers that support that yet.
although as you can't do typename typename it might need another typedef in between.
If I get it correctly you want ClassA to get an instantiation of BaseSubscriber, for example BaseSubscriber<my_tag> and ClassB on an instantiation of BasePublisher. is it correct?
If your answer is yes, then why you declare template argument of ClassA and ClassB as template, you don't want to do something with it in ClassA or ClassB, so it should be a class not a templated class:
template<class T>
class BasePublisher
{
// compiling
typedef BaseSubscriber<T> SubscriberTypeT;
};
template< class SubscriberT > class ClassA : SubscriberT {};
template< class PublisherT >
class ClassB : PublisherT {
void method1( ClassA<typename PublisherT::SubscriberTypeT> );
};

How do we typedef or redefine a templated nested class in the subclass?

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;
}