A class:
template<typename C, typename T>
class A
{
template <typename U>
class Nested{};
Nested<T> n;
};
And I want to specialize Nested. Here what I tried:
template<typename C, typename T>
class A
{
template <typename U>
class Nested{};
template <>
class Nested<int>{}; // by my logic this should work by I have a compilation error "explicit specialization in non-namespace scope 'class A<C, T>'"
Nested<T> n;
};
My next attempt:
template<typename C, typename T>
class A
{
template <typename U>
class Nested{};
Nested<T> n;
};
template<>
A<>::Nested<int>{}; // What is the correct syntax to do it here? Now I have an error "wrong number of template arguments (0, should be 2)"
Here on stackoverflow I found a solution:
template<typename C, typename T>
class A
{
template <typename U, bool Dummy = true>
class Nested{}; // why need of this Dummy??
template <bool Dummy>
class Nested<int, Dummy>{}; // why need to provide an argument??
Nested<T> n;
};
It perfectly works, but I can't understand how. Why to provide a dummy template argument? Why can't I use raw specialization template<> class Nested<int, true>{} or template<> class Nested<int>{}?
It's forbidden to create explicit specialization in class-scope:
An explicit specialization shall be declared in a namespace enclosing
the specialized template.
But it's not forbidden to create partial specialization:
A class template partial specialization may be declared or redeclared
in any namespace scope in which its definition may be defined (14.5.1
and 14.5.2).
this
template <bool Dummy>
class Nested<int, Dummy>{}; // why need to provide an argument??
is partial specialization and it's allowed to create such specialization in class-scope. You also cannot fully specialize nested class, in not-specialized outer class. You can do this:
template<>
template<>
class A<int, double>::Nested<int>
{
};
but you cannot do
template<typename C, typename T>
template<>
class A<C, T>::Nested<int>
{
};
I managed to get this to work, by defining all the contents of the specialized template class within the outer class. So all functions are completely defined withing the class definition. No external function definitions, as that did not seem to complile. I.e.
template <typename T, size_t N>
class A
{
private:
template <size_t M>
class B
{
...
};
template <>
class B<2>
{
...
};
... etc
};
It worked on MS2015 at least. Code is running just fine.
Related
It's easy to write template function override with concept, but I don't know how to write template class partial specialization :(
template <typename T>
concept Integral = is_integral_v<T>;
template <typename T>
concept IsNotIntegral = !
is_integral_v<T>;
template <typename T>
class Test
{
};
template <Integral T> // wrong
class Test
{
};
template <typename T> // wrong
requires Integral<T>
class Test
{
};
int main()
{
Test<int> t;
}
This doesn't work either:(
template <Integral T>
class Test
{
};
template <IsNotIntegral T>
class Test
{
};
Both
template <Integral T> // wrong
class Test
{
};
and
template <typename T> // wrong
requires Integral<T>
class Test
{
};
are using the declaration syntax of a primary class template, not a partial specialization. Compare the syntax of an unconstrained partial specialization from before concepts:
// primary class template
template <typename T>
class Test
{
};
// partial specialization of the class template
template <typename T>
class Test<T*>
{
};
The difference is that there isn't just a class name in the partial specialization after the class keyword, but a template-id Test<T*> instead. Without it a partial specialization makes no sense since we wouldn't know what template arguments we are specializing for.
So with constraints the syntax for a partial specialization should be the same:
template <Integral T>
class Test<T>
{
};
or
template <typename T>
requires Integral<T>
class Test<T>
{
};
How to partially specialize nested class without partially specializing the nesting class?
Implementation of class C is the same for all N.
Implementation of C::iterator is special for N=1.
template<class T, int N>
class C
{
class iterator;
...
};
template<class T, int N>
class C<T, N>::iterator
{
...
};
// Partial specialization doesn't compile:
template<class T>
class C<T, 1>::iterator
{
...
};
I can partially specialize class C for N=1, but that's a lot of code duplication...
If you do not want to specialize whole class then just move the iterator out of class and make it template:
template<class T, int N>
class C_iterator
{
...
};
If needed make your specializations:
template<class T>
class C_iterator<T, 1>
{
...
};
Then use it in your class as iterator, if needed befriend it:
template<class T, int N>
class C
{
using iterator = C_iterator<T, N>;
friend iterator;
...
};
The reason is that:
template<class T>
class C<T, 1>::iterator {
// ...
}
Attempts to be the definition for a member class iterator on a partial specialisation for C, where no such partial specialisation exists. The exact same issue would happen if you tried this with a non-static data member, a member function, or a member template: C++ does not allow partial specialisations where only the outer class is partially specialised.
For example, this compiles:
template<class T, int N>
class C {
class iterator; // (A)
};
template<class T>
class C<T, 1> {
class iterator; // (B)
};
template<class T, int N>
class C<T, N>::iterator {}; // Definition for entity declared at (A)
template<class T>
class C<T, 1>::iterator {}; // Definition for entity declared at (B) *not a partial template specialisation
Whereas without the partial specialisation near (B), there is nothing for the second definition to define. As a general rule of thumb, a partial specialisation can only refer to the innermost entity, so it must be a template.
(Note this has nothing to do with what kind of entity iterator is: The same issue would have happened if iterator was a template class and you try to partially specialise it based on N=1)
So the simplest answer is: you can't do exactly what you want to do.
The simplest solution is what Öö Tiib's answer is: Lift the class out and make iterator a member type alias.
For fun, you could make iterator a template class so you can partially specialise it. You still can't partially specialise the outer class only, so I use a constraint to emulate it:
template<class T, int N>
class C
{
template<std::nullptr_t = nullptr>
class iterator;
};
template<class T, int N>
template<std::nullptr_t>
class C<T, N>::iterator
{
};
template<class T, int N>
template<std::nullptr_t dummy> requires (N==1)
class C<T, N>::iterator<dummy>
{
};
// The first is a primary definition, the second a partial specialisation
// (Could have also made them both partial specialisations, with the first `requires (N!=1)`)
By re declare the iterator class, You can get the same result.
template<class T, int N>
class C
{
class iterator {};
};
template<class T>
class C<T, 1>
{
class iterator {};
};
It should be separated from the common working part of the class. (unless you want to rewrite it)
template<class T>
class CWork
{
};
template<class T, int N>
class C : public CWork<T>
{
class iterator {};
};
template<class T>
class C<T, 1> : public CWorkDefine
{
class iterator {};
};
Is there any way to make a template specialization for fundamental types only?
I have tried to do the following:
template<typename T, typename = typename std::enable_if<!std::is_fundamental<T>::value>::type>
class foo
{
}
template<typename T, typename = typename std::enable_if<std::is_fundamental<T>::value>::type>
class foo
{
}
But I'm getting an error that the template is already defined.
Here you are creating two templated classes with the same name, not specializations.
You need to create a generic one and then specialize it:
// not specialized template (for non-fundamental types), Enabler will
// be used to specialize for fundamental types
template <class T, class Enabler = void>
class foo { };
// specialization for fundamental types
template <class T>
class foo<T, std::enable_if_t<std::is_fundamental<T>::value>> { };
I read in many articles, that for class template when specializing
member template, the class that containing specialized member template also shall be explicitly specialized. Is there a point about it in standard and is there any reason to have such restriction?
I mean under the hood.
Why this is not allowed.
template <typename T>
class A
{
template <typename U>
void foo()
{}
};
template <typename T>
template <>
void A<T>::foo<int>()
{}
[temp.expl.spec]/16:
In an explicit specialization declaration for a member of a class
template or a member template that appears in namespace scope, the
member template and some of its enclosing class templates may remain
unspecialized, except that the declaration shall not explicitly
specialize a class member template if its enclosing class templates
are not explicitly specialized as well. [ Example:
template <class T1> class A {
template<class T2> class B {
template<class T3> void mf1(T3);
void mf2();
};
};
template <> template <class X>
class A<int>::B {
template <class T> void mf1(T);
};
template <> template <> template<class T>
void A<int>::B<double>::mf1(T t) { }
template <class Y> template <>
void A<Y>::B<double>::mf2() { } // ill-formed; B<double> is specialized
// but its enclosing class template A is not
— end example ]
suppose I write a template class with a template constructor, like that.
template<typename T>
class X{
template<typename S>
X(X<S> x){}
};
compiles fine. However, when I try to define the constructor outside of the template declaration, like this:
template<typename T>
class X{
template<typename S>
X(X<S> x);
};
template<typename T, typename S>
X<T>::X(X<S> y){}
I receive the following error:
error: invalid use of incomplete type ‘class X<T>’
why? Is it not possible to define a template constructor of a template class outside of the class declaration?
You have two levels of templates, and have to specify them separately.
template<typename T>
template<typename S>
X<T>::X(X<S> y){}
Try this:
template<typename T>
template<typename S>
X<T>::X()( X<S> y )
{
}
Your class has a single template parameter, and you essentially have a template function inside of it, so you need
template<typename T>
template <typename S>
X<T>::X(X<S> y){}