Can I make a template specialisation that inherits from its base? - c++

In other words: Is it possible to make a template specialisation that inherits from its base, like this:
template <class T>
class A{};
template <>
class A<int>:public A<>{};
so that A has all of A's functions?
I'm new here, so I dunno how to format, just in case the code comes up incorrectly.

You can, with a bit of trickery. This pattern is sometimes called “template subclassing” and is used extensively in the SeqAn library.
The trick is to give the base class an additional template argument tag which determines the type identity:
template <typename T, typename Spec = void>
struct A { … };
// inheritance tag:
struct Derived { };
template <typename T>
struct A<T, Derived> : public A<T, void> { … };
Here, void denotes the base (you could also use a dedicated tag Base but void works fine) and Derived, an empty struct, denotes the derived class.
Now you can instantiate and use the templates as follows:
A<int> the_base;
A<int, Derived> the_derived;
the_base.do_something();
the_derived.do_something();
For a real-world example, consider the String class from SeqAn:
String<Dna> some_dna = "GATTACA";
String<Dna, Packed> more_dna = "GATTACA";
The second type derived from the first one, but is a specialisation which packs its characters as tightly as possible (for DNA, this means putting four DNA characters in each byte).

Related

C++ Concepts: Checking if derived from a templated class with unknown template parameter

Is there a way to use C++ concepts to require that a class is derived from a templated class, whose template parameter is again a derived class from another templated class.
Example:
template <class T>
class A{};
template <class T>
class B{};
class X{};
class Y : public A<X> {};
class Z : public B<Y> {};
How can I check in B, that T is of the form std::is_base_of<A<X>,T> for some X without specifying what X is?
I don't want to add X to the template paramter list of B, because I don't want to change code at every instance where B is derived from (e.g. the last line with class Z).
If you want to check for specialisations of A specifically, that isn't too difficult.
template <class C>
concept A_ = requires(C c) {
// IILE, that only binds to A<...> specialisations
// Including classes derived from them
[]<typename X>(A<X>&){}(c);
};
The lambda is basically just a shorthand for a function that is overloaded to accept A specialisations. Classes derived from such specialisations also count towards it. We invoke the lambda with an argument of the type we are checking... and the constraint is either true or false depending on whether the call is valid (the argument is accepted).
Then, just plug it in:
template <A_ T>
class B{};
Here it is working live.
Inspired by answer by #StoryTeller - Unslander Monica, I wrote more general concept which is customisable for any expected template class.
However, you might first ask yourself, whether it makes actually sense to restrict the template type? It makes your design less flexible, so that you can't later e.g. inject mock types for unit testing. IMHO it's usually better to write a concept, which requires your type to adhere to some specific contract (contain some member functions, constants, aliases, etc.) rather than to actually be a concrete class.
Having said that, here's the generalised solution:
/**
* #brief Checks if class type Specialisation (the implicit concept
* argument) is indeed a specialisation of TemplateClass type
* (e.g. satisfied for TemplateClass=SomeLibrary and
* Specialisation=SomeLibrary<A, B>). Also accepts classes
* deriving from specialised TemplateClass.
*
* #tparam PartialSpecialisation optional partial specialisation
* of the TemplateClass to be required
*/
template<class Specialization, template<typename> class TemplateClass,
typename ...PartialSpecialisation>
concept Specializes = requires (Specialization s) {
[]<typename ...TemplateArgs>(
TemplateClass<PartialSpecialisation..., TemplateArgs...>&){}(s);
};
Then for your use case:
template <Specializes<A> T>
class B{};
or even require specific partial specialisation of the desired class:
template<typename ...Args>
struct SomeBase {};
struct A {};
struct B {};
template<Specializes<SomeBase, A> BaseT>
struct Container {};
Container<SomeBase<A, B>> {}; // fine, first template arg is A
Container<SomeBase<B, B>> {}; // error, first template arg isn't A
See working live example here.

How to restrict a method template parameter to types which appear in the template arguments of enclosing structure? [duplicate]

Suppose I have this variadic base class-template:
template <typename ... Types>
class Base
{
public:
// The member foo() can only be called when its template
// parameter is contained within the Types ... pack.
template <typename T>
typename std::enable_if<Contains<T, Types ...>::value>::type
foo() {
std::cout << "Base::foo()\n";
}
};
The foo() member can only be called when its template-parameter matches at least one of the parameters of Base (the implementation of Contains is listed at the bottom at this post):
Base<int, char>().foo<int>(); // fine
Base<int, char>().foo<void>(); // error
Now I define a derived class that inherits twice from Base, using non-overlapping sets of types:
struct Derived: public Base<int, char>,
public Base<double, void>
{};
I was hoping that when calling e.g.
Derived().foo<int>();
the compiler would figure out which base-class to use, because it is SFINAE'd out of the one that does not contain int. However, both GCC 4.9 and Clang 3.5 complain about an ambiguous call.
My question then is two-fold:
Why can't the compiler resolve this ambiguity (general interest)?
What can I do to make this work, without having to write Derived().Base<int, char>::foo<int>();? EDIT: GuyGreer showed me that the call is disambiguated when I add two using-declarations. However, since I'm providing the base-class for the user to inherit from, this isn't an ideal solution. If at all possible, I don't want my users to have to add those declarations (which can be quite verbose and repetitive for large type-lists) to their derived classes.
Implementation of Contains:
template <typename T, typename ... Pack>
struct Contains;
template <typename T>
struct Contains<T>: public std::false_type
{};
template <typename T, typename ... Pack>
struct Contains<T, T, Pack ...>: public std::true_type
{};
template <typename T, typename U, typename ... Pack>
struct Contains<T, U, Pack ...>: public Contains<T, Pack...>
{};
Here's a simpler example:
template <typename T>
class Base2 {
public:
void foo(T ) { }
};
struct Derived: public Base2<int>,
public Base2<double>
{};
int main()
{
Derived().foo(0); // error
}
The reason for that comes from the merge rules [class.member.lookup]:
Otherwise (i.e., C does not contain a declaration of f or the resulting declaration set is empty), S(f,C) is
initially empty. If C has base classes, calculate the lookup set for f in each direct base class subobject Bi,
and merge each such lookup set S(f,Bi) in turn into S(f,C).
— [..]
— Otherwise, if the declaration sets of S(f,Bi) and S(f,C) differ, the merge is ambiguous...
Since our initial declaration set is empty (Derived has no methods in it), we have to merge from all of our bases - but our bases have differing sets, so the merge fails. However, that rule explicitly only applies if the declaration set of C (Derived) is empty. So to avoid it, we make it non-empty:
struct Derived: public Base2<int>,
public Base2<double>
{
using Base2<int>::foo;
using Base2<double>::foo;
};
That works because the rule for applying using is
In the declaration set, using-declarations are replaced by the set
of designated members that are not hidden or overridden by members of the derived class (7.3.3),
There's no comment there about whether or not the members differ - we effectively just provide Derived with two overloads on foo, bypassing the member name lookup merge rules.
Now, Derived().foo(0) unambiguously calls Base2<int>::foo(int ).
Alternatively to having a using for each base explicitly, you could write a collector to do them all:
template <typename... Bases>
struct BaseCollector;
template <typename Base>
struct BaseCollector<Base> : Base
{
using Base::foo;
};
template <typename Base, typename... Bases>
struct BaseCollector<Base, Bases...> : Base, BaseCollector<Bases...>
{
using Base::foo;
using BaseCollector<Bases...>::foo;
};
struct Derived : BaseCollector<Base2<int>, Base2<std::string>>
{ };
int main() {
Derived().foo(0); // OK
Derived().foo(std::string("Hello")); // OK
}
In C++17, you can pack expand using declarations also, which means that this can be simplified into:
template <typename... Bases>
struct BaseCollector : Bases...
{
using Bases::foo...;
};
This isn't just shorter to write, it's also more efficient to compile. Win-win.
Though I can't tell you in detail why it doesn't work as is, I added using Base<int, char>::foo; and using Base<double, void>::foo; to Derived and it compiles fine now.
Tested with clang-3.4 and gcc-4.9

Disambiguate class-member in multiple inheritance

Suppose I have this variadic base class-template:
template <typename ... Types>
class Base
{
public:
// The member foo() can only be called when its template
// parameter is contained within the Types ... pack.
template <typename T>
typename std::enable_if<Contains<T, Types ...>::value>::type
foo() {
std::cout << "Base::foo()\n";
}
};
The foo() member can only be called when its template-parameter matches at least one of the parameters of Base (the implementation of Contains is listed at the bottom at this post):
Base<int, char>().foo<int>(); // fine
Base<int, char>().foo<void>(); // error
Now I define a derived class that inherits twice from Base, using non-overlapping sets of types:
struct Derived: public Base<int, char>,
public Base<double, void>
{};
I was hoping that when calling e.g.
Derived().foo<int>();
the compiler would figure out which base-class to use, because it is SFINAE'd out of the one that does not contain int. However, both GCC 4.9 and Clang 3.5 complain about an ambiguous call.
My question then is two-fold:
Why can't the compiler resolve this ambiguity (general interest)?
What can I do to make this work, without having to write Derived().Base<int, char>::foo<int>();? EDIT: GuyGreer showed me that the call is disambiguated when I add two using-declarations. However, since I'm providing the base-class for the user to inherit from, this isn't an ideal solution. If at all possible, I don't want my users to have to add those declarations (which can be quite verbose and repetitive for large type-lists) to their derived classes.
Implementation of Contains:
template <typename T, typename ... Pack>
struct Contains;
template <typename T>
struct Contains<T>: public std::false_type
{};
template <typename T, typename ... Pack>
struct Contains<T, T, Pack ...>: public std::true_type
{};
template <typename T, typename U, typename ... Pack>
struct Contains<T, U, Pack ...>: public Contains<T, Pack...>
{};
Here's a simpler example:
template <typename T>
class Base2 {
public:
void foo(T ) { }
};
struct Derived: public Base2<int>,
public Base2<double>
{};
int main()
{
Derived().foo(0); // error
}
The reason for that comes from the merge rules [class.member.lookup]:
Otherwise (i.e., C does not contain a declaration of f or the resulting declaration set is empty), S(f,C) is
initially empty. If C has base classes, calculate the lookup set for f in each direct base class subobject Bi,
and merge each such lookup set S(f,Bi) in turn into S(f,C).
— [..]
— Otherwise, if the declaration sets of S(f,Bi) and S(f,C) differ, the merge is ambiguous...
Since our initial declaration set is empty (Derived has no methods in it), we have to merge from all of our bases - but our bases have differing sets, so the merge fails. However, that rule explicitly only applies if the declaration set of C (Derived) is empty. So to avoid it, we make it non-empty:
struct Derived: public Base2<int>,
public Base2<double>
{
using Base2<int>::foo;
using Base2<double>::foo;
};
That works because the rule for applying using is
In the declaration set, using-declarations are replaced by the set
of designated members that are not hidden or overridden by members of the derived class (7.3.3),
There's no comment there about whether or not the members differ - we effectively just provide Derived with two overloads on foo, bypassing the member name lookup merge rules.
Now, Derived().foo(0) unambiguously calls Base2<int>::foo(int ).
Alternatively to having a using for each base explicitly, you could write a collector to do them all:
template <typename... Bases>
struct BaseCollector;
template <typename Base>
struct BaseCollector<Base> : Base
{
using Base::foo;
};
template <typename Base, typename... Bases>
struct BaseCollector<Base, Bases...> : Base, BaseCollector<Bases...>
{
using Base::foo;
using BaseCollector<Bases...>::foo;
};
struct Derived : BaseCollector<Base2<int>, Base2<std::string>>
{ };
int main() {
Derived().foo(0); // OK
Derived().foo(std::string("Hello")); // OK
}
In C++17, you can pack expand using declarations also, which means that this can be simplified into:
template <typename... Bases>
struct BaseCollector : Bases...
{
using Bases::foo...;
};
This isn't just shorter to write, it's also more efficient to compile. Win-win.
Though I can't tell you in detail why it doesn't work as is, I added using Base<int, char>::foo; and using Base<double, void>::foo; to Derived and it compiles fine now.
Tested with clang-3.4 and gcc-4.9

Why use a specialised template class?

This occured in the line of thought following Template specialization or conditional expressions?.
I am using template specialisation in a project of mine and came across this example from Stroustrup: Matrix.h, where he declares a MatrixBase template class
template<class T> class Matrix_base
for common elements and a Matrix template class
template<class T = double, int D = 1> class Matrix
as a "prop" (whatever that is) for specialisations. He declares the constructor as private so that only specialisations can be instanciated. These are declared:
template<class T> class Matrix<T,1> : public Matrix_base<T> {...};
template<class T> class Matrix<T,2> : public Matrix_base<T> {...};
template<class T> class Matrix<T,3> : public Matrix_base<T> {...};
My question is: In this case, what is the advantage of specialisation? Obviously there is no code that the three specialisations have in common, so why not cut out the general template and declare:
template<class T> class Matrix_1<T> : public Matrix_base<T> {...};
template<class T> class Matrix_2<T> : public Matrix_base<T> {...};
template<class T> class Matrix_3<T> : public Matrix_base<T> {...};
?
Because by having the second template parameter, one allows for specializations as well as a general, non-specialized implementation. So
Matrix<float, 1000> m;
might do something reasonable but non specialized, whereas you would have to define a Matrix_1000<T>.
Edit: the first point applies in general, but not to this particular case, where the general case has a private constructor.
Furthermore, it allows you to do stuff like
Matrix<double, SOME_CONSTANT> m;
which you cannot do with your _N solution.
Basically the answer is that you can use the template in generic code. You can use a compile time constant to change the behavior of the program, or you can write generic code that will handle different versions of the Matrix class that could not be handled if the types had different names:
template <typename T, int D>
void print( std::ostream& o, Matrix<T,D> const & m ) { ...
That is, even though you need to explicitly create the different types, the specialization mechanism allows you to provide a single name that can be used generically to manage the different types as if they are just variants of one single type.

Variable of a template class with a template class template parameter set to a base template of the derived template with the variable

I'm attempting to have a derived class (normal template) that has a variable of a template type that has as its template class parameter the type of a base class (normal template, same parameter as the derived class) of the derived class (the one with the variable). This makes VC++ incredibly angry at me, and I am incapable of calming its fury. Here's a quick example:
template<template<typename VT> class CT, typename VT> struct encapThing {};
template<typename VT> struct innocuousBase {};
template<typename VT> struct derivOfDoom : public innocuousBase<VT>
{
encapThing<innocuousBase, VT> ohgodhelp; //C3200
};
It will throw a C3200, saying it expected a class template. Now, I can see why this might be thinking there is a recursive loop of templates within templates, even if this isn't actually the case. How can I convince VC++ otherwise?
Unqualified use of innocuousBase inside of derivOfDoom<> is interpreted as innocuousBase<VT>, much as unqualified use of derivOfDoom in that context would be interpreted as derivOfDoom<VT>. I don't remember offhand whether or not this is standard-conformant behavior, but the workaround is trivial: fully qualify innocuousBase so the compiler knows you're referring to the innocuousBase class template and not the innocuousBase<VT> base class:
template<typename VT> struct derivOfDoom : innocuousBase<VT>
{
encapThing<::innocuousBase, VT> ohgodhelp;
};