Template Specialization Based on Inherit Class

Template specialization and inheritance

Nicol's solution works fine, but this is an alternative:

template<typename T>
struct Base
{
void print1() {cout << "Base::print1" << endl;};
void print2() {cout << "Base::print2" << endl;};
};

template<>
void Base<int>::print2() {cout << "Base<int>::print2()" << endl;};

That way you can specialize only specific member functions and still use those that you haven't specialized(in this case, print1) without any problem. So now you'd use it just like you wanted:

Base<int> i;
i.print1();
i.print2(); // calls your specialization

Demo here.

Template specialization based on inherit class

This article describes a neat trick: http://www.gotw.ca/publications/mxc++-item-4.htm

Here's the basic idea. You first need an IsDerivedFrom class (this provides runtime and compile-time checking):

template<typename D, typename B>
class IsDerivedFrom
{
class No { };
class Yes { No no[3]; };

static Yes Test( B* ); // not defined
static No Test( ... ); // not defined

static void Constraints(D* p) { B* pb = p; pb = p; }

public:
enum { Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };

IsDerivedFrom() { void(*p)(D*) = Constraints; }
};

Then your MyClass needs an implementation that's potentially specialized:

template<typename T, int>
class MyClassImpl
{
// general case: T is not derived from SomeTag
};

template<typename T>
class MyClassImpl<T, 1>
{
// T is derived from SomeTag
public:
typedef int isSpecialized;
};

and MyClass actually looks like:

template<typename T>
class MyClass: public MyClassImpl<T, IsDerivedFrom<T, SomeTag>::Is>
{
};

Then your main will be fine the way it is:

int main()
{
MyClass<SomeTag>::isSpecialized test1; //ok
MyClass<InheritSomeTag>::isSpecialized test2; //ok also
return 0;
}

Template specialization and inheritance template class from other template class

  1. Class specialization Derived<T(P)> inherits from class template<typename T> class Base or from class template<typename T, typename P> class Base<T(P)>?

Technically, neither. A class or class template never inherits from a template, only from one specific base class type. That is, Derived<int(float&)> inherits Base<int(float&)>, and so on. That base class gets instantiated from whatever is the most specialized declaration associated with Base for those specific types. The importance of this distinction comes up if there are additional partial specializations or explicit specializations.

If I change your example a bit,

template<typename T> // #1
class Base;

template<typename T, typename P> // #2
class Base<T(P)> {
public:
static const int mem1 = 1;
};

template<typename T>
class Derived;

template<typename T, typename P>
class Derived<T(P)> : public Base<T(P)> {
};

class SomethingElse {};

template<typename P> // #3
class Base<SomethingElse(const P&)> {
public:
static const long long mem2 = 2;
};

using ThingType = Derived<SomethingElse(const std::string&)>;
const auto A = ThingType::mem1; // Error!
const auto B = ThingType::mem2; // OK

It's not correct to say that partial specialization Derived<T(P)> inherits partial specialization Base<T(P)>, since the example type Derived<SomethingElse(const std::string&)> uses that Derived partial specialization, but doesn't use that Base partial specialization at all. Base<T(P)> just means the template called Base, with whatever specialization definition for Base best matches the template argument T(P). The decision about what the base class Base<T(P)> means is made independently for each specific set of template arguments when each specialization of Derived is instantiated.


  1. What the name of when I'm binding template parameters T and P of class specialization Derived<T(P)> with template parameter T of class Base.

I don't know of any term for this, other than that you are using a dependent compound type. (Dependent = depends on one or more template parameters; Compound = the type T(P) involves the other types T and P.) This also makes Base<T(P)> a dependent base class in the definition of Derived<T(P)>, meaning the compiler will not look there for plain identifiers, and you need to use this->name or Base::name to make such names valid. It's also important that the template parameters are in "deducible contexts" within the specialization's template arguments.

Template explicit specialization in class using inheritance

This will compile if you add a public template definition of fun in Derived.

But that will probably not do what you want.
In particular d.fun<bool>(); will not execute the implementation in Base, but the implementation in Derived.

You cannot specialize template functions in derived classes.

You also cannot use subtype polymorphism on template functions: template cannot be virtual.

You can achieve some type of static polymorphism using CRTP.

Yes removing templates and working with separated functions would work (a.toX()...).

Another option is to work with overloads (i.e. passing a dummy argument or the destination variable and write different implementations).

Adding an example for the dummy argument solution as requested:

namespace TO {
static const bool BOOL = false;
static const double DOUBLE = 0.0;
static const int INT = 0;
}

struct A {
bool convert(bool dummy) {
return true;
}
};

struct B : public A {
using A::convert; // important

int convert(int dummy) {
return 2;
}

double convert(double dummy) {
return 3.0;
}
};

int main() {
B b;
std::cout << b.convert(TO::BOOL) << std::endl;
std::cout << b.convert(TO::DOUBLE) << std::endl;
std::cout << b.convert(TO::INT) << std::endl;
}

With this kind of solution there is a risk of implicit conversion when calling the function. toX() might be a safer option.

Specialization of inherited nested template class

Clang and GCC are wrong, and MSVC and EDG are right to reject that partial specialization definition.

A partial specialization is itself a template, and a class template definition is syntactically constructed in terms of a class definition (in grammar terms, a class-specifier). Within such a definition, Derived::Inner<int, _> is a class-head-name, with Derived:: being a nested-name-specifier.

[9p11] in the Standard says:

If a class-head-name contains a nested-name-specifier, the
class-specifier shall refer to a class that was previously declared
directly in the class or namespace to which the nested-name-specifier
refers, or in an element of the inline namespace set (7.3.1) of that
namespace (i.e., not merely inherited or introduced by a
using-declaration), and the class-specifier shall appear in a
namespace enclosing the previous declaration. [...]

So, you have to use Base::Inner<int, _>.


As noted in the comments, the quote above applies to class template explicit specialization definitions as well (their grammar production also ends up using class-head-name).


The following doesn't apply directly to your example, but I found it worth mentioning.

Note that the quote above refers to class template (or explicit specialization) definitions, not declarations such as

template<class _> struct Derived::Inner<int, _>;

Syntactically, struct Derived::Inner<int, _> in there is an elaborated-type-specifier, to which the paragraph above doesn't apply. So, the Standard wording technically allows such declarations.

This doesn't seem to be an oversight: the wording above was introduced by the resolution of DR284, which includes the comment:

The sentiment was that this should be required on class definitions,
but not on elaborated type specifiers in general (which are
references, not declarations). [...]

The proposed resolution included elaborated-type-specifiers, but those were removed from the final wording.

However, neither MSVC nor EDG accept such declarations (and frankly I'd find it confusing if they did). The comment in the DR seems to indicate that the intent was to allow only elaborated-type-specifiers that are not also declarations, but it looks like this wasn't reflected in the wording (a Standard bug, I think).

C++ - Is there a way for a template class specialization to contain code from the general template?

Is it possible for a template specialization to 'inherit' (without actual C++ inheritance) members like a and getA() from A? 

Short answer: no.

Long answer: no, A is a class template and thus it's not something from which you can inherit members (either data or functions).

Moreover, what you are asking for sounds like - how can I defeat the whole purpose of a specialization?. Well, go with inheritance from a base class for members that don't depend on template parameters. That's the more straightforward way to do that and what the language offers you.

You cannot just inherit a member function from a type without extending that type.

There a lot of techniques to achieve the purpose: direct inheritance, mixin, inherit-from-above idiom and so on.

All of them go through inheritance to compose interfaces. I don't see why one should demonize it.

C++ template partial specialization with inheritance

This seems to work for me.

template <typename A, typename B>
struct Foo;

template <typename A, typename B>
struct FooBase
{
Foo<A, B>& func0()
{
cout << "FooBase:func0\n";
return static_cast<Foo<A, B>&>(*this);
}

void func1() { cout << "FooBase::func1\n"; }
void func2() { cout << "FooBase::func2\n"; }
};

template <typename A, typename B>
struct Foo : public FooBase<A, B> {
};

template <typename A>
struct Foo<A, int> : public FooBase<A, int>
{
void func2() { cout << "Foo<A, int>::func2\n"; }
void func3() { cout << "Foo<A, int>::func3\n"; }
};

If you wind up needing the definition of Foo within FooBase, you may need to use the CRTP trick of passing the derived class as a template parameter to FooBase, but for simple things I think the forward declaration is sufficient.



Related Topics



Leave a reply



Submit