Specialization of member class nested in a non-specialized class - c++

template <typename T>
struct A
{
template <typename U>
struct B;
template <>
struct B<int> {static const int tag = 1;}; // Works fine in VS2010
};
How can I specialize B the same way, but outside of A. I tried this with no success :
template <typename T> template <>
struct A<T>::B<int> {static const int tag = 1;};
I get:
error C3212: 'A<T>::B<int>' : an explicit specialization of a template member must be a member of an explicit specialization
It does not make sense since I can do exactly that by defining it inside the class
VS2010 problem? Wrong syntax?
Thanks
PS: This one (which should be wrong anyway, crashes VS2010):
template <> template <typename T>
struct A<T>::B<int> {static const int tag = 1;};

To quote the C++ spec, ยง14.17.3.18:
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 unspecialzed, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. [...]
(my emphasis)
This suggests that you can't specialize a template class nested inside another template class unless the outer template class is specialized as well. So it looks like VS2010 has this behavior wrong and g++ has it right.

It just doesn't work that way.:-(
You cannot specialize a function inside the class declaration, even though msvc accepts this with its default settings.
You also cannot specialize a member function without also specializing the enclosing class. Most compilers avred on this (as does the language standard).

Related

Static assert in template specialization fails even if it is not instantiated

The following code compiles fine:
#include <type_traits>
template <typename T> struct dependent_true : std::true_type { };
template <typename T> struct dependent_false : std::false_type { };
template <bool B = false>
class X { static_assert(dependent_false<X>::value); };
template <>
class X<true> { static_assert(dependent_true<X>::value); };
int main() {
X<true> x;
}
That is, the static_assert in the primary template is not evaluated. On the contrary, if I switch to:
template <bool B = false>
class X { static_assert(dependent_true<X>::value); };
template <>
class X<true> { static_assert(dependent_false<X>::value); };
int main() {
X<false> x;
}
Then, the static assertion in template specialization fails, even if it is not instantiated. I just wonder why. I observed this behavior with GCC 8 and Clang 6 (-std=c++17).
Live demo: https://wandbox.org/permlink/MOWNLnGMgmuDA2Ht
template <> class X<true> {/* ... */}; - is not a template anymore.
[temp.expl.spec]/5
A member of an explicitly specialized class is not implicitly
instantiated from the member declaration of the class template;
instead, the member of the class template specialization shall itself
be explicitly defined if its definition is required. In this case, the
definition of the class template explicit specialization shall be in
scope at the point at which the member is defined. The definition of
an explicitly specialized class is unrelated to the definition of a
generated specialization. That is, its members need not have the same
names, types, etc. as the members of a generated specialization.
Members of an explicitly specialized class template are defined in the
same manner as members of normal classes, and not using the template<>
syntax. The same is true when defining a member of an explicitly
specialized member class. However, template<> is used in defining a
member of an explicitly specialized member class template that is
specialized as a class template.
The specialization is just like a regular class. It's not a template, and nothing is dependent. Therefore dependent_false<X>::value is just a constant expression that evaluates immediately to false. So the static assertion is immediately triggered.
Even non-instantiated template parts should be valid C++ code. static_assert(false) makes the program ill-formed. So you have your specialization with static_assert which is known on compile time to be false and your program becomes ill-formed. You have no non-resolved template parameters on your class which is used in static_assert to make compiler wonder; it knows exactly that it is false.
The same goes to if constexpr, you also can't use static_assert with expressions known to be false even if the part where this static_assert is located always gets discarded.

How to initialize a static const member of type depending on T in a templated class?

Given the following class
template <class T>
class A {
static const B<T> member;
};
how can I instantiate member for each class A<T> separately?
Simple. As you would with any other static non-integral type.
template <class T>
class A {
static const B<T> member;
};
template <class T>
const B<T> A<T>::member/*(optional-args)*/;
In order to allocate member differently for different types of T, you must use template specialisation.
To start the template specialisation you must use this syntax:
template<>
// ... explicit definition
The syntax for the explicit definition is basically the same syntax as:
template <class T>
const B<T> A<T>::member/*(optional-args)*/;
Except, instead of template <class T>, you use template<>, and where T is, you put the actual type.
For example:
template<>
const B<type> A<type>::member(args);
NOTE: If you wish to call the default constructor with template specialisation in this scenario, please see the EDIT below.
You can substitute type for any type you wish. With this you can provide different arguments for each possible type. Although if you specialise too much, you should consider if your design is really suited to use templates.
Here it is in action (online), feel free to clone and play around with it.
I thought I'd mention that the declaration must be where the template class is located. In other words, if A is declared in the header, you must also declare the allocation for member in the header file. You can alternatively use an inline file (.inl) and #include the .inl file in the header file that the template class is declared.
EDIT:
It seems that in C++98, the following syntax to call the default constructor does not compile under GCC or clang, if you refer to the member variable:
template <>
const B<type> A<type>::member/*()*/;
Where type is any type.
However the following does:
template <class T>
const B<T> A<T>::member/*()*/;
I'm not sure if this is a bug, or just incorrect syntax.
I recommend instead to do the following:
template <>
const B<type> A<type>::member = B<type>();
Or if you are using C++11, you can use curly brackets to call the default-constructor, like so:
template <>
const B<type> A<type>::member{};
If you use regular brackets, the compiler will thing it is a static function within the A<type> class, and if you use no brackets, you will get an undefined reference to 'A<type>::member' linker error. Which you can see here.
Here is the discussion that Aaron and I discovered this error.

what does template<> (without any class T in the <>) mean?

I'm reading some source code in stl_construct.h,
In most cases it has sth in the <>
and i see some lines with only "template<> ...".
what's this?
This would mean that what follows is a template specialization.
Guess, I completely misread the Q and answered something that was not being asked.
So here I answer the Q being asked:
It is an Explicit Specialization with an empty template argument list.
When you instantiate a template with a given set of template arguments the compiler generates a new definition based on those template arguments. But there is a facility to override this behavior of definition generation. Instead of compiler generating the definition We can specify the definition the compiler should use for a given set of template arguments. This is called explicit specialization.
The template<> prefix indicates that the following template declaration takes no template parameters.
Explicit specialization can be applied to:
Function or class template
Member function of a class template
Static data member of a class template
Member class of a class template
Member function template of a class template &
Member class template of a class template
It's a template specialization where all template parameters are fully specified, and there happens to be no parameters left in the <>.
For example:
template<class A, class B> // base template
struct Something
{
// do something here
};
template<class A> // specialize for B = int
struct Something<A, int>
{
// do something different here
};
template<> // specialize both parameters
struct Something<double, int>
{
// do something here too
};

Difference between instantiation and specialization in c++ templates

What is the difference between specialization and instantiation in context of C++ templates. From what I have read so far the following is what I have understood about specialization and instantiation.
template <typename T>
struct Struct
{
T x;
};
template<>
struct Struct <int> //specialization
{
//code
};
int main()
{
Struct <int> s; //specialized version comes into play
Struct <float> r; // Struct <float> is instantiated by the compiler as shown below
}
Instantiation of Struct <float> by the compiler
template <typename T=float>
struct Struct
{
float x;
}
Is my understanding of template instantiation and specialization correct?
(Implicit) Instantiation
This is what you refer to as instantiation (as mentioned in the Question)
Explicit Instantiation
This is when you tell the compiler to instantiate the template with given types, like this:
template Struct<char>; // used to control the PLACE where the template is inst-ed
(Explicit) Specialization
This is what you refer to as specialization (as mentioned in the Question)
Partial Specialization
This is when you give an alternative definition to a template for a subset of types, like this:
template<class T> class Struct<T*> {...} // partial specialization for pointers
What is the difference between specialization and instantiation in context of C++ templates?
Normally (no specializations present) the compiler will create instantiations of a template when they are used, by substituting actual template parameters (int in your example) for the formal template parameters (T) and then compile the resulting code.
If a specialization is present, then for the (set of) special template parameter(s) specified by that specialization, that specialization's implementation is to be used instead of what the compiler would create.
Overview
Specialization: The class, function or class member you get when substituting template arguments into the template parameters of a class template or function template.
Instantiation: The act of creating a specialization out of a template or class template member. The specialization can be created out of a partial specialization, class template member or out of a primary class or function template.
An explicit specialization is one that defines the class, function or member explicitly, without an instantiation.
A template specialization actually changes the behaviour of the template for a specific type. eg convert to a string:
template<typename T> std::string convertToString( const T& t )
{
std::ostringstream oss;
oss << t;
return oss.str();
}
Let's specialise that though when our type is already a std::string as it is pointless going through ostringstream
template<> std::string convertToString( const std::string & t )
{
return t;
}
You can specialise for classes too.
Now instantiation: this is done to allow you to move the compilation for certain types into one compilation unit. This can save you both compilation time and sometimes code-bloat too.
Let's say we make the above into a class called StringConvert rather than a function.
template<typename T>
class StringConvert
{
public:
// 4 static functions to convert from T to string, string to T,
// T to wstring and wstring to T using streams
};
We will convert a lot of integers to strings so we can instantiate it: Put this inside one header
extern template class StringConvert<int>;
Put this inside one compilation unit:
template class StringConvert<int>;
Note that the above can also be done (without the extern in the header) with functions that are actually not implemented inline. One of your compilation units will implement them. However then your template is limited only to instantiated types. Sometimes done when the template has a virtual destructor.
In c++ 11.
instantiation:
Instantiate the template with given template arguments
template <typename T>
struct test{ T m; };
template test<int>;//explicit instantiation
which result in a definition of a struct with a identifier test<int>
test<int> a;//implicit instantiation
if template <typename T> struct test has been instantiated with argument T = int before(explicit or implicit), then it's just a struct instantiation. Otherwise it will instantiate template <typename T> struct test with argument T = int first implicitly and then instantiate an instance of struct test<int>
specialization:
a specialization is still a template, you still need instantiation to get the real code.
template <typename T>
struct test{ T m; };
template <> struct test<int>{ int newM; } //specialization
The most useful of template specialization is probably that you can create different templates for different template arguments which means you can have different definitions of class or function for different template arguments.
template<> struct test<char>{ int cm; }//specialization for char
test<char> a;
a.cm = 1;
template<> struct test<long> { int lm; }//specialization for long
test<long> a;
a.lm = 1;
In addition to these full template specializations above, there(only class template) exits partial template specialization also.
template<typename T>
struct test {};
template <typename T> struct test<const T>{};//partial specialization for const T
template <typename A, typename B>
struct test {};
template <typename B> struct test<int, B>{};//partial specialization for A = int
A specialized template is no longer just a template. Instead, it is either an actual class or an actual function.
A specialization is from either an instantiation or an explicit specialization, cf 14.7.4 below.
An instantiation is based on a primary template definition. A sample implicit class template instantiation,
template<typename T>
class foo {}
foo<int> foo_int_object;
A sample explicit class template instantiation,
template class foo<double>;
An explicit specialization has a different definition from it's primary template.
template<>
class foo<bool> {}
// extract from standard
14 Templates
14.7 Template instantiation and specialization
4 An instantiated template specialization can be either implicitly instantiated (14.7.1) for a given argument
list or be explicitly instantiated (14.7.2). A specialization is a class, function, or class member that is either
instantiated or explicitly specialized (14.7.3).

Full specialization of method template from class template

I know this subject should be pretty much dated by now, but I'm having a tough time with this specific case.
Straight to the point, this is what I want to do:
enum MyEnum
{
E_1,
E_2
};
template <MyEnum T>
class MyClass
{
// method to be fully specialized
template <typename U>
void myMethod(U value);
};
// full specialization of method template from class template
// (or is this in fact partial, since I'm leaving T alone?)
template <MyEnum T>
template <>
void MyClass<T>::myMethod<int>(int value)
{
std::cout << value << '\n';
}
Is this possible?
C++03 [$14.7.3/18] says
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.
So you need to specialize the enclosing class too.
Something like this would work.
template <>
template <>
void MyClass<E_1>::myMethod<int>(int value)
{
std::cout << value << '\n';
}
Since you leave T, while specializing only function template, then what you're trying to do would be called partial specialization, because T is still templated and you can use it in your function. But unfortunately, partial template specialization of function (whether be it member function or non-member function) is not allowed. So your code would give compilation error.
Either you fully specialize by specializing the class template as well, or you don't at all.