How to avoid a "template template template" template in c++ - c++

I have tried to implement a "template template template" - template class to fullfill my needs ( I am quite new in using template metaprogramming). Unfortunately, I have found the following topic too late:
Template Template Parameters
Nevertheless, I need to implement something like listed below.
According to the compiler the last typedef is not working. I am not sure, but I think this is due to the limitation of 3x template restriction. Is there any possibility to bypass a 3xtemplate definition in this simple example?
template < typename TValueType >
class ITTranslator
{
public:
ITTranslator() = 0;
virtual ~ITTranslator() = 0;
virtual void doSomething() = 0;
}
template < typename TValueType >
class TConcreteTranslator1 : public ITTranslator<TValueType>
{
public:
TConcreteTranslator1(){}
~TConcreteTranslator1(){}
void doSomething() {}
}
template < typename TValueType >
class TConcreteTranslator2 : public ITTranslator<TValueType>
{
public:
TConcreteTranslator2(){}
~TConcreteTranslator2(){}
void doSomething() {}
}
template <
typename TValueType,
template < typename TValueType > class TTranslatorValueType
>
class ITClassifier
{
public:
ITClassifier() = 0;
virtual ~ITClassifier() = 0;
}
template <
typename TValueType,
template < typename TValueType > class TTranslatorValueType
>
class TConcreteClassifier1 : public ITClassifier<TValueType,TTranslatorValueType >
{
public:
TConcreteClassifier1() {}
~TConcreteClassifier1() {}
void dodo(){}
}
template <
typename TValueType,
template <typename TValueType> class TTranslatorValueType,
template <template<typename TValueType> class TTranslatorValueType> class TClassifierValueType
>
class ITAlgorithm
{
public:
ITAlgorithm()=0;
virtual ~TAlgorithm()=0;
virtual run() = 0;
}
template <
typename TValueType,
template <typename TValueType> class TTranslatorValueType,
template <template<typename TValueType> class TTranslatorValueType> class TClassifierValueType
>
class TConcreteAlgorithm1 : public ITAlgorithm<TValueType,TTranslatorValueType,TTranslatorValueType>
{
public:
TConcreteAlgorithm1 (){}
~TConcreteAlgorithm1 (){}
run()
{
TClassifierValueType< TTranslatorValueType>* l_classifier_pt = new TClassifierValueType< TTranslatorValueType>( );
// add this object to a internal list...
}
}
int main()
{
typedef TConcreteTranslator1< cvbase::uint32_t > translator_t;
typedef TConcreteClassifier1< cvbase::uint32_t, TConcreteTranslator1> classifier_t;
typedef TConcreteAlgorithm1 < cvbase::uint32_t, TConcreteTranslator1, TConcreteClassifier1> algorithm_t; // not possible
return 0;
}
Thanks a lot, I really appreciate any help!
EDIT:
I have extended my listing (I am pretty sure it will not compile :)) to show the motivation why I am using my weird concept :)

There is really no need to pass template template parameter around
here. Usually you can just take a normal template argument and provide
a reasonable default:
template<typename ValueType>
struct translator {};
template<typename ValueType, typename Translator = translator<ValueType>>
struct Classifier {};
template<typename ValueType,
typename Translator = translator<ValueType>,
typename Classifier = classifier<ValueType, Translator>
>
struct Algorithm {};
This is done the same way for allocator aware containers.
And please do away with the horrible hungarian-notation prefixes.
NB: It seems from your usage of constructors and destructors that you
don't really have a grasp of basic C++. You might want to stay away
from templates before you have understood easier concepts.

Yes it is possible to avoid template template parameters (of any level).
A template is basically a type-level function. You feed it a type, and get another type back.
A template template parameter is itself a type-level function, and a template that accepts such parameter is a higher-order type-level function.
It is possible to implement higher-order type-level functions with member templates, without ever using template template parameters. I'm not really sure you need it for your design, but here's a quick and dirty example:
// regular type, a.k.a. zeroth-order type-level function,
// a.k.a. "type of kind *"
struct N
{
int a;
};
// a first-order type-level function, a.k.a. "type of kind *->*"
// it is wrapped in a regular type
struct B
{
template <class A> struct Impl
{
void foo(A a)
{
int aa = a.a;
}
};
};
// a second-order type-level function
// that accepts a (wrapped) first-order type function
// and also a regular type. the kind of it would be (*->*)->*->*
// it applies its first argument to its second argument
struct Z
{
template <class X, class Y> struct Impl
{
typename X::template Impl<Y> ya;
void bar()
{
ya.foo(Y());
}
};
};
// now this is something: a third-order type-level function
// that accepts a (wrapped) second-order type-level function
// and a (wrapped) first-order type-level function
// and a zeroth-order type-level function
// it applies its first argument to its second and third arguments
// it is also wrapped in a regular type for consistency
// try to figure out its kind
struct T
{
template <class P, class Q, class R> struct Impl
{
typename P::template Impl<Q, R> yb;
void baz()
{
yb.bar();
}
};
};
T::Impl<Z, B, N> tt;

In this case you don't really need to have template parameters, basically the only variable type is TValueType right?
The other types can be resolved on the class body using TValueType.
Something like this:
template <
typename TValueType
>
class TAlgorithm
{
public:
// TTranslator <TValueType> whatever
// TTranslatorValueType <TValueType> whatever
TAlgorithm(){}
~TAlgorithm(){}
}

Related

Template specialization for the base template type for future derived types

I have a class that works as wrapper for some primitives or custom types. I want to write explicit specialization for custom template type.
My code that reproduces the problem:
template < class T >
struct A {
void func() { std::cout << "base\n"; }
};
template <>
struct A<int> {};
template < class T, class CRTP >
struct BaseCrtp {
void someFunc() {
CRTP::someStaticFunc();
}
};
struct DerrType : BaseCrtp<int, DerrType> {
static void someStaticFunc() {}
};
template < class T, class CRTP >
struct A< BaseCrtp<T, CRTP> > {
void func() { std::cout << "sometype\n"; }
};
int main() {
A<DerrType> a;
a.func(); // print: "base". should be: "sometype"
return 0;
}
A<DerrType> use default function, not a specialization. How can I make specialization for these set of classes?
I will have a lot of types like DerrType, and I want to make common behavior for all of them.
DerrType and others will be used as curiously recurring template pattern
Not sure I fully understood what you want, but maybe something like this:
template<typename T>
concept DerivedFromBaseCrtp = requires(T& t) {
[]<typename U, typename CRTP>(BaseCrtp<U, CRTP>&){}(t);
};
template < DerivedFromBaseCrtp T >
struct A<T> {
void func() { std::cout << "sometype\n"; }
};
The concept basically checks whether T is equal to or is publicly inherited (directly or indirectly) from some specialization of BaseCrtp. Otherwise the call to the lambda would be ill-formed. Template argument deduction only succeeds in the call if the argument and parameter type match exactly or the argument has a derived type of the parameter. If the class is inherited non-publicly, the reference in the call can't bind to the parameter.
The concept will however fail if the type is inherited from multiple BaseCrtp specializations, in which case template argument deduction on the call will not be able to choose between the multiple choices.
Alternatively you can also use the stricter concept
template<typename T>
concept CrtpDerivedFromBaseCrtp = requires(T& t) {
[]<typename U>(BaseCrtp<U, T>&){}(t);
};
which will also require that the type T is actually using the CRTP pattern on BaseCrtp (directly or through a some base class between BaseCrtp and T). Again, this will fail if T is inherited multiple times from some BaseCrtp<U, T> specialization, although it will ignore specializations with a type other than T in the second position.
For another alternative you might want to check that T is derived from some type X such that X is derived from BaseCrtp<U, X> for some U (meaning that X uses the CRTP pattern correctly). That could be done using this variation:
template <typename T>
concept CrtpDerivedFromBaseCrtp =
requires(T& t) {
[]<typename U, typename CRTP>(BaseCrtp<U, CRTP>&)
requires(std::is_base_of_v<CRTP, T> &&
std::is_base_of_v<BaseCrtp<U, CRTP>, CRTP>)
{}
(t);
};
Again, this fails if T is derived from multiple BaseCrtp specializations, directly or indirectly.

C++: Extraction of template types

I am working on a compile-time wrapper library and stumbled upon a problem of extracting a template parameter type from a given type.
The situation is the following. I have an unchangeable class R:
template <class T>
class R {};
I also have an unchangeable main function:
int main()
{
auto r = new R<int>();
// Function that knows the type of 'r'
create_obj<decltype(r)>();
delete r;
return 0;
}
The create_obj function is the one that I am working on. For visualization purposes, I will write it the following way:
template< class C >
void create_obj()
{
// Print the type of the function (Output: R<int>*)
std::cout << boost::typeindex::type_id<C>().pretty_name() << std::endl;
}
And the problem is that I need to access the int template parameter type of the R class from the create_obj function.
Pseudocode:
template<
template < class T >
class C<T>
>
void create_obj()
{
// Print the type of the function (Output: int)
std::cout << boost::typeindex::type_id<T>().pretty_name() << std::endl;
}
Is it possible to do it? I was going through the C++ documentation but I was not able to find any way to "detach" the template parameter type from the class definition.
Yes, it is possible, one way to do it:
template<typename T>
class R{};
template<typename C>
struct extract_impl{};
template<typename T>
struct extract_impl<R<T>>{
using type = T;
};
template<typename C>
using extracted_type = typename extract_impl<std::remove_pointer_t<std::decay_t<C>>>::type;
template< class C >
void create_obj()
{
static_assert(std::is_same_v<extracted_type<C>,int>);
}
int main()
{
create_obj<R<int>>();
}
The convention is that R would itself expose the type via using, but you wrote that it is unchangeable.
I instead calling create_obj() through the type of r
create_obj<decltype(r)>();
you can call it passing directly r, the solution is simple
template <typename T>
void create_obj (R<T> const *)
{ /* do something with T */ }
But if you want call create_obj() passing only the type R<T> (or a type pointer to R<T>) without instantiating an object of type R<T>, you can define a lightweight type wrapper
template <typename>
struct typeWrapper
{ /* empty! */ };
redefine create_obj() receiving a typeWrapper of a R<T> pointer
template <typename T>
void create_obj (typeWrapper<R<T> *> const &)
{ /* do something with T */ }
and call it using decltype(r)
create_obj(typeWrapper<decltype(r)>{});
or directly R<int> *
create_obj(typeWrapper<R<int> *>{});
Another alternative is declare create_obj as a struct/class
template <typename>
struct create_obj;
and define only a specialization based on a R<T> * pointer, with a static func() method in it
template <typename T>
struct create_obj<R<T> *>
{
static void func ()
{ /* do something with T */ }
};
You can use it through decltype(r)
create_obj<decltype(r)>::func();
or through R<int> *
create_obj<R<int> *>::func();
If you prefer, instead of a static func() method, you can insert in create_obj() an ordinary (non static) method; maybe an operator(). But, this way, you have to instantiate a create_obj object to call the method.

Template specialization of a single method from templated class with multiple template parameters

I'm basically trying to do what was discussed in Template specialization of a single method from a templated class except that my TClass has multiple template Parameters like this:
template < class KEY, class TYPE >
class TClass
{
public:
:
void doSomething(KEY * v);
:
};
template < class KEY, class TYPE >
void TClass<KEY, TYPE>::doSomething(KEY * v)
{
// do something
}
This works so far, but how do I define a specialized implementation for one template Parameter? I tried adding this:
template < class TYPE >
void TClass<int, TYPE>::doSomething(int * v)
{
// do something if KEY is int
}
but the Compiler complains about "unable to match function Definition to an existing declaration" (VC2010) for that method/function.
As a sidenote: If I specialize both template Parameters at the same time, it works:
template < >
void TClass<int, char>::doSomething(int * v)
{
// do something if KEY is int and TYPE is char
}
but that's not what I want to do.
Any suggestions?
You have to specialize the entire class before you define a method through a partial specialization:
template <typename T, typename U>
class TClass;
template <typename T>
class TClass<int, T>
{
void doSomething(int* v);
};
template <typename T>
void TClass<int, T>::doSomething(int* v)
{
// ...
}
Live demo
You can fully specialize class method but as far as I remember you can't partially specialize it.
You can try partial specialization for the whole class but this will probably involve a lot of duplication.

Don't have access to template template parameters

Why can't I do this:
template<template<class E>class Derived>
struct X
{
static void f()
{
Derived<E>::value;
}
};
The problem that I have is that I cannot compile this code for the reason that I'm getting an error saying that param E hasn't been declared. Is there a way that I can use this formal param or not?
Parameters of template template parameters don't get arguments, and therefore don't usually have names. Partial specialization is the exception to this rule. Try this instead:
template<class> // Derived<E> is only only parameter
struct X; // but you actually need two parameters, Derived and E
template< template <class> class Derived, class E >
struct X< Derived< E > > // so use partial specialization.
{
static void f()
{
Derived<E>::value; // only reason to want this is to
Derived<int>::value; // use different specializations
}
};
Of course, if you don't need to re-specialize on Derived< something_else >, just ignore the fact that Derived<E> is a template specialization:
template<class Derived>
struct X
{
static void f()
{
Derived::value;
}
};
X< my_class< something > > my_x; // a specialized class template is a class
Your template parameter Derived is a template itself, E is its formal parameter.
You need to pass a value for it, too.
Maybe you need the following:
template<template<class E>class Derived, class T>
struct X
{
static void f()
{
Derived<T>::value;
}
};
You can't use that parameter because it is just there to mean that Derived is a template with exactly one type argument.
You'd call f like this:
template <class T>
struct ZZZ {};
X<ZZZ>::f();
^^^
Note that there is no E in this instantiation.
Unless there is a reason to use template templates, you could just use a regular template, else you'll need to pass E as a separate argument, making the call look like this:
X<ZZZ, int>::f();
You just have your syntax a bit muddled.
template<class E>
struct X
{
static void f()
{
Derived<E>::value;
}
}
should work fine.

Incomplete type as function parameter?

I have that template class that uses a policy for it's output and another template argument to determine the type for it's data members. Furthermore the constructor takes pointers to base classes which are stored in private pointers. Functions of this objects shall take a this pointer to the template class to give them access to the data. In code this looks like this:
class ShapeGenerator;
template <typename PointData, typename OutputPolicy> class ModelCreator {
private:
OutputPolicy output;
ShapeGenerator* shape
std::vector<PointData> data;
public:
ModelCreator (ShapeGenerator *s) : shape(s) { }
void createShape() { shape->generateShape(this); }
};
ShapeGenerator is an interface and shall be implemented. It looks like this:
class ShapeGenerator {
public:
void generateShape (ModelCreator* m) = 0;
};
If I compile this with g++ 4.3.4 (cygwin) I get an error in the ShapeGenerator::generateShape saying 'ModelCreater' is not a type. I put in a forward declaration of ModelCreator but it changed nothing. I played with some combinations of types and parameters, for example passing only the vector and then I got an error message that said something about incomplete types. I guess this is the problem here.
So, is it possible to pass a templated type with without specific arguements? If so, how?
edit:
I'm not bound to the ModelCreator typename. If I have to write it more template-like this isn't problem. But I would like not to specify the types of ModelCreator in the ShapeCreator object. Is that possible?
edit2:
Ok, I guess I was a bit to optimistic with this "design". It would have been nice to just throw in some ingrediences and get a soup. But now the salt has to know about the kind of water in the pot. I'll change the templates to plain old composition. Thanks you guys.
If you want to use the ModelCreator with "free" template parameters, then you have to make ShapeGenerator a template too:
template <typename PointData, typename OutputPolicy>
class ShapeGenerator {
public:
void generateShape (ModelCreator<PointData,OutputPolicy>* m) = 0;
};
or
template <template <typename, typename> class ModelCreator>
class ShapeGenerator {
public:
void generateShape (ModelCreator* m) = 0;
};
The second version takes another template as a parameter. You would use it like this:
ShapeGenerator<ModelCreator<PointDataType,OutPutPolicyType> > shapeGenerator;
You need to make ShapeGenerate a template class as well:
template <typename PointData, typename OutputPolicy>
class ShapeGenerator;
template <typename PointData, typename OutputPolicy>
class ModelCreator {
private:
OutputPolicy output;
ShapeGenerator< PointData, OutputPolicy >* shape;
std::vector<PointData> data;
public:
ModelCreator (ShapeGenerator< PointData, OutputPolicy >* s) : shape(s) { }
void createShape();
};
template <typename PointData, typename OutputPolicy>
class ShapeGenerator {
public:
void generateShape (ModelCreator< PointData, OutputPolicy> * m) = 0;
};
template <typename PointData, typename OutputPolicy>
void ModelCreator< PointData, OutputPolicy >::createShape() { shape->generateShape(this); }