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 )
{
}
Related
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 {};
};
I have the following template class :
template <typename T>
class myClass
{
public:
// Many methods...
protected:
private:
T attribute
// Other attributes.
};
Instantiating an object of type myClass<void> does not work, because of void attribute.
Can you give me some hints to be able to use objects of type myClass<void> without specializing the whole class. Since it has many member functions that rely on the type T, specializing it will lead to code duplication.
Create a templated base class containing attribute, specialize it for void and inherit from it:
namespace detail //Warn end user that he should not use stuff from here
{
template <typename T>
struct myClass_base
{
T attribute;
};
template <>
struct myClass_base<void>
{}; //No attribute at all
}
template <typename T>
class myClass: private detail::myClass_base<T>
{
//rest of definition
};
This would make myClass lack attribute field when instantiating it with type void
You can defer the whole problem by using a custom type and specializing that:
template<typename T>
struct my_type_t
{
using type = T;
};
template<>
struct my_type_t<void>
{};
template<typename T>
using my_type = typename my_type_t<T>::type;
template <typename T>
class myClass
{
public:
// Many methods...
protected:
private:
my_type<T> attribute
// Other attributes.
};
Then at least you don't have to duplicate the whole rest of the class again.
But it probably does not make that much sense, as you surely want to use the type somewhere. So you would have to specialize that places further.
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 )
{
}
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 )
{
}
I wondering if something similar to this is possible. Basically, I have a templated class that occasionally takes objects of templated classes. I would like to specialize it (or just a member function)for a specific templated class, but the 'generic' form of that class.
template<typename T, typename S>
class SomeRandomClass
{
//put something here
};
template<typename T>
class MyTemplateClass
{
void DoSomething(T & t) {
//...something
}
};
template<>
void MyTemplateClass< SomeRandomClass<???> >::DoSomething(SomeRandomClass<???> & t)
{
//something specialized happens here
}
Replacing the question marks with appropriate types (double, etc) works, but I would like it to remain generic. I don't know what to put there, as any types wouldn't have been defined. I've looked around, and learned about template template parameters, and tried various combinations to no avail. Thanks for the help!
It's possible to specialize the class like this
template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
void DoSomething(SomeRandomClass<T,S>& t) { /* something */ }
};
It's not possible to specialize just the member method, because the specialization is on the class as a whole, and you have to define a new class. You can, however, do
template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
void DoSomething(SomeRandomClass<T,S>& t);
};
template <>
template <typename T,typename S>
void MyTemplateClass<SomeRandomClass<T,S> >::DoSomething(SomeRandomClass<T,S>& t)
{
// something
}
to split up the declaration and definition.
I'm not completely sure why #Ryan Calhoun specialized the way he did but here's a more terse example:
// class we want to specialize with later on
template<typename T, typename S>
struct SomeRandomClass
{
int myInt = 0;
};
// non-specialized class
template<typename T>
struct MyTemplateClass
{
void DoSomething(T & t)
{
std::cout << "Not specialized" << std::endl;
}
};
// specialized class
template<typename T, typename S>
struct MyTemplateClass< SomeRandomClass<T, S> >
{
void DoSomething(SomeRandomClass<T,S> & t)
{
std::cout << "Specialized" << std::endl;
}
};
You can see that you don't need the redundant syntax used in the accepted answer:
template<>
template<typename T, typename S>
Working Demo
Alternative
You can use type_traits and tag-dispatch within your non-specialized class to specialize just the function.
Let's first make a concept for is_random_class:
// concept to test for whether some type is SomeRandomClass<T,S>
template<typename T>
struct is_random_class : std::false_type{};
template<typename T, typename S>
struct is_random_class<SomeRandomClass<T,S>> : std::true_type{};
And then let's declare our MyTemplateClass again, but this time not templated (because we're not specializing) so we'll call it MyNonTemplatedClass:
class MyNonTemplatedClass
{
public:
template<typename T>
void DoSomething(T & t)
{
DoSomethingHelper(t, typename is_random_class<T>::type());
}
// ...
Notice how DoSomething is now templated, and it's actually calling a helper instead of implementing the logic itself?
Let's break down the line:
DoSomethingHelper(t, typename is_random_class<T>::type());
t is as-before; we're passing along the argument of type T&
typename is_random_class<T>::type()
is_random_class<T> is our concept, and since it derives from std::true_type or std::false_type it will have a ::type defined within the class (Google for "type traits")
::type() 'instantiates' the type specified by is_random_class<T>::type. I say it in quotation marks because we're really going to throw that away as we see later
typename is required because the compiler doesn't know that is_random_clas<T>::type actually names a type.
Now we're ready to look at the rest of MyNonTemplatedClass:
private:
//use tag dispatch. If the compiler is smart it won't actually try to instantiate the second param
template<typename T>
void DoSomethingHelper(T&t, std::true_type)
{
std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
}
template<typename T>
void DoSomethingHelper(T&t, std::false_type)
{
std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
}
};
Full Working Demo v2 Here
Notice that our helper functions are named the same, but overloaded on the second parameter's type. We don't give a name to the parameter because we don't need it, and hopefully the compiler will optimize it away while still calling the proper function.
Our concept forces DoSomethingHelper(T&t, std::true_type) only if T is of type SomeRandomClass, and calls the other for any other type.
The benefit of tag dispatch
The main benefit of tag dispatch here is that you don't need to specialize your entire class if you only mean to specialize a single function within that class.
The tag dispatching will happen at compile time, which you wouldn't get if you tried to perform branching on the concept solely within the DoSomething function.
C++17
In C++17, this problem becomes embarrassingly easy using variable templates (C++14) and if constexpr (C++17).
We use our type_trait to create a variable template that will give us a bool value of true if the provided type T is of type SomeRandomClass, and false otherwise:
template<class T>
constexpr bool is_random_class_v = is_random_class<T>::value;
Then, we use it in a if constexpr expression that only compiles the appropriate branch (and discards the other at compile-time, so the check is at compile-time, not run-time):
struct MyNonTemplatedClass
{
template<class T>
void DoSomething(T& t)
{
if constexpr(is_random_class_v<T>)
std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
else
std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
}
};
type-traits were a way to simulate this without needing a class specialization.
Note that is_random_class here is a stand-in for an arbitrary constraint. In general, if you're only checking for a single nontemplated type, prefer a normal overload because it's more efficient on the compiler.
Demo
C++20
In C++20, we can take this a step further and use a constraint instead of if constexpr by using a requires clause on our templated member function. The downside is that we again move back to two functions; one that matches the constraint, and another that doesn't:
struct MyNonTemplatedClass
{
template<class T> requires is_random_class_v<T>
void DoSomething(T& t)
{
std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
}
template<class T> requires !is_random_class_v<T>
void DoSomething(T&)
{
std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
}
};
Demo
Also in C++ 20, we could explicitly encode a concept and use abbreviated template syntax:
template<class T>
concept IsRandomClass = is_random_class_v<T>;
template<class T>
concept IsNotRandomClass = !is_random_class_v<T>;
// ...
template<IsRandomClass T>
void DoSomething(T& t)
{ /*...*/}
template<IsNotRandomClass T>
void DoSomething(T&)
{ /*...*/}
Demo
All you need to do is just template on what you want to keep generic. Taking what you started with:
template<typename T, typename S>
void MyTemplateClass< SomeRandomClass<T,S> >::DoSomething(SomeRandomClass<T,S> & t)
{
//something specialized happens here
}
EDIT:
Alternatively, if you only want to keep part of the SomeRandomClass generic, you could:
template<typename T>
void MyTemplateClass< SomeRandomClass<T,int> >::DoSomething(SomeRandomClass<T,int> & t)
{
//something specialized happens here
}
Edit: this is a correct answer to a different question.
Using the typename T twice confuses the issue a little, because they are compiled separately and are not connected in any way.
You can overload the method to take a templated parameter:
template <typename T>
class MyTemplateClass
{
void DoSomething(T& t) { }
template <typename U,typename V>
void DoSomething(SomeRandomClass<<U,V>& r) { }
};
This maps U and V in the new method to T' and S' in SomeRandomClass. In this setup, either U or V could be the same type as T, but they don't have to be. Depending on your compiler, you ought to be able to do
MyTemplateClass<string> mine;
SomeRandomClass<int,double> random;
// note: nevermind the non-const ref on the string literal here...
mine.DoSomething("hello world");
mine.DoSomething(random);
and the templated call will be selected as the matching overload without having to respecify the types explicitly.
Edit:
To do with with template specialization makes no difference to the overload of DoSomething. If you specialize the class as follows
template <>
class SomeRandomClass <int,double>
{
// something here...
};
then the overload above will eat up this specialized implementation gladly. Just be sure the interfaces of the specialized template and the default template match.
If what you're wanting is to specialize DoSomething to take a specific pair of types for SomeRandomClass then you've already lost generality...that's what specialization is.
If you want to use provide a template struct as a template argument (with intent to use it inside) without specializing it:
Here is an example, that appends a type to a tuple given a template sfinae struct as a template argument:
template<typename Tuple, typename T, template<typename> class /*SFINAEPredicate*/>
struct append_if;
template<typename T, template<typename> class SFINAEPredicate, typename ... Types>
struct append_if<std::tuple<Types...>, T, SFINAEPredicate>
{
using type = typename std::conditional<SFINAEPredicate<T>::value,
std::tuple<Types..., T>, std::tuple<Types...>>::type;
};
// usage
using tuple_with_int = append_if<std::tuple<>, int, std::is_fundamental>;
This can be used since C++11.