Template specializations for inner class - c++

consider the following code :
struct X
{
template <typename T>
class Y
{};
};
template<>
class X::Y<double>{
};
here we are specializing the Y class for the type double and the code works fine. the problem is that if I change the code to this:
template<typename A>
struct X
{
template <typename T>
class Y
{};
};
template<typename A>
class X<A>::Y<double>{
};
the compiler will report an error:
'X::Y': explicit specialization is using partial
specialization syntax, use template <> instead!
dose any one know how can I specialize class Y in this case?

You cannot specialize an inner template class without explicitly specializing the outer one as well. See this question for more details and a quote from the standard.
Workaround: create an outer class that takes both T and A in a detail namespace, and alias it inside X:
namespace impl
{
template <typename A, typename T>
struct Y { };
}
template<typename A>
struct X
{
template <typename T>
using Y = impl::Y<A, T>;
};
If you are fine with explicitly specializing both inner and outer class, you can use the following syntax:
template <>
template <>
class X<int>::Y<double>
{
// ...
};
Example on wandbox

The simple answer - you can't fully specialize templated inner class of templated outer class. But if you really want to achieve similar effect you could try partial specialization with dummy defaulted template parameter:
#include <iostream>
template<typename A>
struct X
{
template <typename T, T* =nullptr>
class Y{};
};
template<typename A>
template<double *Ptr>
class X<A>::Y<double, Ptr> {
public:
static constexpr int value = 1;
};
int main() {
std::cout << X<int>::Y<double>::value << std::endl;
}
[live demo]

Related

Call templated class with multiple parameters with single parameter only

I have a class with multiple template parameters; let us say it looks something like this:
template <class T, class B>
struct Vector2 : B
{
Vector2() noexcept;
constexpr explicit Vector2(T a) noexcept;
}
Template parameter B always depends on T. For example if T is float B will be XMFLOAT2, if T is int B will be XMINT2. For this I created a template specialization:
template class Vector2<float, XMFLOAT2>;
template class Vector2<int32_t, XMINT2>;
template class Vector2<uint32_t, XMUINT2>;
The problem is that since B always depends on T, I want to call Vector<float> for example, and the expression should expand to Vector<float, XMFLOAT2>.
I thought of doing a typealias, however, I wouldn't be sure how to accomplish this, since it would need to be specialized again.
template<class T> using Vector2 = Vector2<T, ??>;
That doesn't really make sense...
How can I call a class with multiple template parameters using just a single parameter with the others being deduced? Or is there a different approach?
You can create helper trait:
template <typename T>
struct vector_base_class;
template <> struct vector_base_class<float> { using type = XMFLOAT2; };
template <> struct vector_base_class<int32_t> { using type = XMINT2; };
template <> struct vector_base_class<uint32_t> { using type = XMUINT2; };
template <class T>
struct Vector2 : typename vector_base_class<T>::type
{
Vector2() noexcept;
constexpr explicit Vector2(T a) noexcept;
};
As mentioned in a comment, you are probably looking for a trait:
template <typename T>
struct xm_from_T;
template <class T, class B = typename xm_from_T<T>::type>
struct Vector2 : B
{
Vector2() noexcept;
constexpr explicit Vector2(T a) noexcept;
};
Then specialize the trait:
template <> struct xm_from_T<float> { using type = XMFLOAT2; };
template <> struct xm_from_T<int32_t> { using type = XMINT2; };
template <> struct xm_from_T<uint32_t> { using type = XMUINT2; };

If template parameter AA is a templatized class A<T> itself, is it possible to get the template parameter (T) of this templatized class?

Consider the code below:
template <typename T>
class A{
...
}
template <class U>
class B{
...
}
int main {
B<A<int>> a;
...
}
How can I get the template parameter of A (int in this case) inside B, if A<int> is the template parameter for B?
I could parametrize B as follows, but I feel like I am sending an unnecessary piece of information.
template <class AA, typename T>
class B { ... }
The reason I do not simply use template <typename T> for class B is that I have a pointer to class A inside B, and I want to use the template parameter class AA to see if that pointer is const or not, hence have the correct type for the member pointer in B.
There are several ways, depending of that you might change:
Quick way, specialize B
template <class> class B;
template <class T>
class B<A<T>>
{
// Use directly T
//...
};
Add info in A directly (as std containers do with value_type)
template <typename T>
struct A
{
using my_type = T;
};
// Then in `B<U>`, use `typename U::my_type`
Use external traits to extract information from A (as std::iterator_traits) (that also allows to handle built-in types):
template <typename T>
struct ATrait;
template <typename T>
struct ATrait<A<T>>
{
using my_type = T;
};
// Possibly a generic one
template <template <typename> class C, typename T>
struct ATrait<C<T>>
{
using my_type = T;
};
// Then in `B<U>`, use `typename ATrait<U>::my_type`
I think the following does what you want:
#include<type_traits>
template<class>
class A{};
template<class>
struct get_inner;
template<template<class> class TT, class T>
struct get_inner<TT<T>> {
using outer = TT<T>;
using inner = T;
};
template<class TT>
struct B {
using A = TT;
using inner = typename get_inner<std::decay_t<A>>::inner;
};
int main(int argc, char *argv[])
{
static_assert(std::is_const_v<typename B<const A<int>>::A>);
static_assert(!std::is_const_v<typename B<A<int>>::A>);
}
Note the std::decay_t, it wouldn't work with the const parameter directly (hence we cannot just specialize B in this way). Maybe decay_t is a bit strong but it works^^
Try this
template <typename X> class B;
template <template <typename> class XX, typename T>
class B<XX<T>>
{
// your implementation
};
B<A<int>> a;

Metaprogramming with std::is_same

Is it possible to do something like the following that compiles without template specialization?
template <class T>
class A {
public:
#if std::is_same<T, int>
void has_int() { }
#elif std::is_same<T, char>
void has_char() { }
#endif
};
A<int> a; a.has_int();
A<char> b; b.has_char();
Yes. Make the function templates and then conditionaly enable them using std::enable_if:
#include <type_traits>
template <class T>
class A {
public:
template<typename U = T>
typename std::enable_if<std::is_same<U,int>::value>::type
has_int() {}
template<typename U = T>
typename std::enable_if<std::is_same<U,char>::value>::type
has_char() {}
};
int main()
{
A<int> a;
a.has_int(); // OK
// a.has_char(); // error
}
The solution from the other answer might not be feasible if the class is big and has got many functions that need to regardless of T. But you can solve this by inheriting from another class that is used only for these special methods. Then, you can specialize that base class only.
In C++14, there are convenient type aliases so the syntax can become:
std::enable_if_t<std::is_same<U, int>::value>
And C++17, even shorter:
std::enable_if_t<std::is_same_v<U, int>>
Yes, with template specialization :
template <class T>
class A;
template <>
class A<int>
{
void had_int(){}
};
template <>
class A<char>
{
void had_char(){}
};

No class template named X in templated class

When tryin to compile this (CRTP-like) code with GCC 4.6.0:
template<template<class> class T> struct A;
template<class T>
struct B: A<B<T>::template X> {
template <class U> struct X { U mem; };
};
B<int> a;
I get the errormessage "test.cpp:3:26: error: no class template named ‘X’ in ‘struct B<int>’". Why does X seem to be invisible outside the class definition?
As Emile Cormier correctly points out here the problem is that at the place of instantiation of A, B is still an incomplete type, and you cannot use the inner template.
The solution for that is moving the template X outside of the template B. If it is independent of the particular instantiation T of the template B, just move it to the namespace level, if it is dependent on the instantiation, you can use type traits:
template <typename T>
struct inner_template
{
template <typename U> class tmpl { U mem; }; // can specialize for particular T's
};
template <typename T>
struct B : A< inner_template<T>::template tmpl >
{
};
struct B is still considered an incomplete type when you specify A<B<T>::template X> as the base class.
You're trying to use a member of B as a parent of B creating a recursive-esque situation. For example this doesn't compile either:
template<template<class> class T> struct A {};
struct B : public A<B::nested>
{
struct nested {};
};

Is it possible to specialize a template using a member enum?

struct Bar {
enum { Special = 4 };
};
template<class T, int K> struct Foo {};
template<class T> struct Foo<T,T::Special> {};
Usage:
Foo<Bar> aa;
fails to compile using gcc 4.1.2
It complains about the usage of T::Special for partial specilization of Foo. If Special was a class the solution would be to a typename in front of it. Is there something equivalent to it for enums (or integers)?
Since that is not allowed by C++ as explained by Prasoon, so an alternative solution would be to use EnumToType class template,
struct Bar {
enum { Special = 4 };
};
template<int e>
struct EnumToType
{
static const int value = e;
};
template<class T, class K> //note I changed from "int K" to "class K"
struct Foo
{};
template<class T>
struct Foo<T, EnumToType<(int)T::Special> >
{
static const int enumValue = T::Special;
};
Sample code at ideone : http://www.ideone.com/JPvZy
Or, you can simply specialize like this (if it solves your problem),
template<class T> struct Foo<T,Bar::Special> {};
//usage
Foo<Bar, Bar::Special> f;
The type of a non-type template argument cannot depend on a template parameter of a partial specialization.
ISO C++03 14.5.4/9 says
A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.
template <int I, int J> struct A {};
template <int I> struct A<I+5, I*2> {}; //error
template <int I, int J> struct B {};
template <int I> struct B<I, I> {}; //OK
So something like this is illegal template<class T> struct Foo<T,T::Special> {}; because T::Special depends on T
The usage is also illegal. You have provided one template argument but you need to provide two.