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 {};
};
Related
Say I have a simple template like this:
template<typename T>
class A {};
And I want to specify that the type-parameter T is of some unrelated type X<U> where U is not known (or unspecifyable).
Is there a way how to express that as a concept?
Is there a way how to express that as a concept?
You don't need a concept, class template specialization works just fine in your case.
As an example, you can do this:
template<typename T>
class A;
template<typename U>
class A<X<U>> { /* ... */ };
This way, unless A is instantiated with a type of the form X<U> (where U is unknown), you'll get a compile-time error because the primary template isn't defined. In other terms, it won't work for all the types but X<U> (for each U), where the latter matches the class template specialization that has a proper definition.
Note that I assumed X is a known type. That's not clear from your question.
Anyway, if it's not and you want to accept types of the form X<U> for each X and each U, you can still do this:
template<typename T>
class A;
template<template<typename> class X, typename U>
class A<X<U>> { /* ... */ };
As a minimal, working example:
template<typename>
struct S {};
template<typename>
class A;
template<typename U>
class A<S<U>> {};
int main() {
A<S<int>> aSInt;
A<S<double>> aSDouble;
// A<char> aChar;
}
Both A<S<int>> and A<S<double>> are fine and the example compiles. If you toggle the comment, it won't compile anymore for A<char> isn't defined at all.
As a side note, if you don't want to use class template specialization and you want to simulate concepts (remember that they are not part of the standard yet and they won't be at least until 2020), you can do something like this:
#include<type_traits>
template<typename>
struct X {};
template<typename>
struct is_xu: std::false_type {};
template<typename U>
struct is_xu<X<U>>: std::true_type {};
template<typename T>
struct A {
static_assert(is_xu<T>::value, "!");
// ...
};
int main() {
A<X<int>> aXInt;
A<X<double>> aXDouble;
// A<char> aChar;
}
That is, given a generic type T, static assert its actual type by means of another structure (is_xu in the example) that verifies if T is of the form X<U> (for each U) or not.
My two cents: the class template specialization is easier to read and understand at a glance.
template <typename T, template <typename> class C>
concept bool Template = requires (T t) { {t} -> C<auto>; };
Now given a class template:
template <typename T>
struct X {};
a type template parameter can be constrained using:
template <typename T> requires Template<T, X>
class A {};
or:
template <Template<X> T>
class A {};
DEMO
This will work also for types derived from X<U>.
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)
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.
I have a primary template, which I need to specialize based on based on a meta-function. The usual idiom is like
template<class T,class E = void>
struct foo { };
template<class T>
struct foo<T,std::enable_if_t<is_xxx<T>{}> > {};
However, I have a situation where the primary template is written as
template<class T>
struct foo { };
(i.e. without that extra SFINAE placeholder) and I am not allowed to change it. What is the best way to specialize it based on a trait( like I can do that mostly for function template based on return type or additional argument)?
You can add a base class:
template<class T, class E = void>
struct foo_base { };
template<class T>
struct foo : foo_base<T, std::enable_if_t<is_xxx<T>{}>> { };
Then you move any members of foo into foo_base.
I'm trying to figure out the correct syntax for explicit specialization of a nested template class. The following code will better illustrate:
struct Column_Major;
struct Row_Major;
template<size_t rows, size_t cols, typename T, typename Allocator>
class Matrix
{
/* bunch of members */
template <typename storage = Column_Major>
class Iterator
{
/* bunch of members */
};
};
I'd like to write an explicit specialization for template <> class Matrix<...>::Iterator<Row_Major, but the syntax is eluding me. I have a suspicion that it is not possible to explicitly specialize the Iterator class without an explicit specialization of the containing class, Matrix. But I would be very happy if there is a way to do this.
I know I could make the Iterator class a separate class, not a member of the Matrix class, but having the classes nested as such allows me full access to the template parameters and datamebers of the Matrix class, which simplifies things. I know I could work around this if I need to, but I'd first like to investigate and understand the possibilities for the nested approach.
Thanks,
Shmuel
For explicit specialization, you need to specialize the outer class before the inner, you can see this question for example.
There is a workaround that is using partial specialization:
template<size_t rows, size_t cols, typename T, typename Allocator>
class Matrix
{
// Notice the additionnal dummy parameter
// vvvvvvvvvvvvv
template <typename storage = Column_Major, bool = true>
class Iterator
{
};
// Specialization
template <bool dummy>
class Iterator<Row_Major, dummy>
{
};
};
You can make Synxis answer (use of defaulted dummy parameter) even more clean with C++11:
/// template <typename X>, not needed for the example
struct Outer
{
private:
template <typename A, typename D = void>
struct Inner
{
Inner() { cout << "default" << endl; }
};
template <typename D>
struct Inner<int,D>
{
Inner() { cout << "int" << endl; }
};
public:
template <typename T>
using Nested = Inner<T>;
};
The advantage of this improvement is that the signature of Nested has only one template parameter, which I think will help if you want to match it correctly in template meta-programming.
I'm surprised the template parameter for the nested class isn't a parameter of the parent class instead.
The nested class can use the template parameters of the parent and this more closely ties the nested class to the parent. Your use of the word iterator suggests this is good, the iterator surely iterating over the same type the parent contains?
I'd do it like this:
template <class T>
class Outer
{
public:
class Inner
{
void Fn( T in )
{
}
};
};
// specialisation
void Outer<double>::Inner::Fn( double in )
{
}