C++ Templates Specialization Syntax

C++ templates specialization syntax

Here are comments with each syntax:

void foo(int param); //not a specialization, it is an overload

void foo<int>(int param); //ill-formed

//this form always works
template <> void foo<int>(int param); //explicit specialization

//same as above, but works only if template argument deduction is possible!
template <> void foo(int param); //explicit specialization

//same as above, but works only if template argument deduction is possible!
template void foo(int param); //explicit instantiation

Added by me:

//Notice <int>. This form always works!
template void foo<int>(int param); //explicit instantiation

//Notice <>. works only if template argument deduction is possible!
template void foo<>(int param); //explicit instantiation

From coding point of view, overload is preferred over function-template-specialization.

So, don't specialize function template:

  • Why Not Specialize Function Templates?
  • Template Specialization and Overloading

And to know the terminologies:

  • instantiation
  • explicit instantiation
  • specialization
  • explicit specialization

See this :

  • Difference between instantiation and specialization in c++ templates

Template class partial specialization syntax

You appear to be confusing partial specialization with default template arguments. It further appears you need both (for reasons unstated, but not really important). Though not entirely intuitive, it can be accomplished as follows:

#include <iostream>

template <typename Key, typename Value = bool>
class KeyValuePair
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "original\n";
}
};

template <typename Key>
class KeyValuePair<Key, bool>
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "specialized\n";
}
};

int main()
{
KeyValuePair<int,int> kvp1;
KeyValuePair<int> kvp2;
}

Output

KeyValuePair<int, int>::KeyValuePair() [Key = int, Value = int]:original
KeyValuePair<int, bool>::KeyValuePair() [Key = int, Value = bool]:specialized

The confusing part to some is the default argument specification, but a template that follows which will never actually see fruition with that default-arg because of the later specialization. In such cases I prefer to forward-declare the template with its default argument list. At least for me it makes it slightly easier to read. You may (or not) choose to do the same if you feel it offers clarity. Something like:

template <typename Key, typename Value = bool>
class KeyValuePair;

template <typename Key, typename Value>
class KeyValuePair
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "original\n";
}
};

template <typename Key>
class KeyValuePair<Key, bool>
{
public:
KeyValuePair()
{
std::cout << __PRETTY_FUNCTION__ << ':' << "specialized\n";
}
};

How does that syntax for defining a full function template specialization a friend of a class?

See C++17 [temp.friend]/1:

A friend of a class or class template can be a function template or class template, a specialization of a function template or class template, or a non-template function or class. For a friend function declaration that is not a template declaration:

  • if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a specialization of a function template, otherwise,
  • if the name of the friend is a qualified-id and a matching non-template function is found in the specified class or namespace, the friend declaration refers to that function, otherwise,
  • if the name of the friend is a qualified-id and a matching function template is found in the specified class or namespace, the friend declaration refers to the deduced specialization of that function template (17.8.2.6), otherwise,
  • the name shall be an unqualified-id that declares (or redeclares) a non-template function.

The names bar<T> and bar<> are both template-ids, so if you use either one, then it refers to a specialization of the function template ::bar. As specified in [temp.arg.explicit]:

Template arguments can be specified when referring to a function template specialization by qualifying the function template name with the list of template-arguments ... A template argument list may be specified when referring to a specialization of a function template ... in a friend declaration. Trailing template arguments that can be deduced (17.8.2) or obtained from default template-arguments may be omitted from the list of explicit template-arguments. ... If all of the template arguments can be deduced, they may all be omitted; ...

Thus, the meaning of bar<> in the friend declaration is that template argument deduction shall be done to determine which specialization of bar is being referred to. Of course, the deduced specialization is the one that takes an argument of the type Foo<T>. So the two declarations with bar<> and bar<T> would have the same meaning.

Template class specialization for vector type - different valid syntax?

Given the definition of the class template,

template<> // <--- optional?
template<typename T>
struct PrintMe<std::vector<T>> { ... };

is not valid.

You need to remove that line and use:

template<typename T>
struct PrintMe<std::vector<T>> { ... };

template specialization for static data member

This isn't an explicitly specialized class template (that would be if you had for example a fully-specialized C<Foo>) so that passage doesn't apply to your code here. You do in fact need template<> for this.

function template specialization syntax for cpp file

The correct syntax depends on what you're actually trying to do. Adding the <> is NOT just a way to fix Doxygen---it substantially changes the meaning of the program!

The following are explicit instantiation definitions:

template void FileReader::Read<uint8_t>( uint8_t * );
template void FileReader::Read<uint16_t>( uint16_t * );

They tell the compiler to instantiate the function template right then and there, and to emit symbols for the instantiations so that they can be linked to by another translation unit. This seems to be what you're actually trying to do.

The following are explicit specialization declarations:

template<> void FileReader::Read<uint8_t>( uint8_t * );
template<> void FileReader::Read<uint16_t>( uint16_t * );

They tell the compiler that you're going to define your own specializations of the template for those particular template arguments. Thus, anyone who tries to call FileReader::Read<uint8_t> will NOT instantiate the primary template that you've already defined, but rather, look for a specialized definition. It doesn't look like that's what you're trying to do, but if it were, you would actually have to define those specializations at some point.

C++ template function explicit specialization with multiple template types

template<bool B, typename T>
void foo(T const&)
{
static_assert(false, "not implemented");
}

template<bool B>
void foo(short)
{
printf("it's a short!\n");
}

However, this is not really specialisation, but overloading, which is completely appropriate. In fact, you could omit the general case.



Related Topics



Leave a reply



Submit