Partial template specialization

Last updated

Partial template specialization is a particular form of class template specialization. Usually used in reference to the C++ programming language, it allows the programmer to specialize only some arguments of a class template, as opposed to explicit full specialization, where all the template arguments are provided.

Contents

Templates and specialization

Class templates are really meta-classes: they are partial abstract data types that provide instructions to the compiler on how to create classes with the proper data members. For example, the C++ standard containers are class templates. When a programmer uses a vector, one instantiates it with a specific data type, for example, int, string or double. Each type of vector results in a different class in the compiler's object code, each one working with a different data type. This process is called monomorphization of generics.

If one knows that a class template will be used with a specific data type fairly often and this data type allows some optimizations (e.g. bit shifting with integers, as opposed to multiplying or dividing by 2), one may introduce a specialized class template with some of the template parameters preset. When the compiler sees such a class template instantiated in code, it will generally choose the most specialized template definition that matches the instantiation. Therefore, an explicit full specialization (one where all the template arguments are specified) will be preferred to a partial specialization if all the template arguments match.

Partial specialization

Templates can have more than one parameter type. Some older compilers allow one only to specialize either all or none of the template's parameters. Compilers that support partial specialization allow the programmer to specialize some parameters while leaving the others generic.

Example

Suppose there exists a KeyValuePair class with two template parameters, as follows.

template<typenameKey,typenameValue>classKeyValuePair{};

The following is an example of a class that defines an explicit full template specialization of KeyValuePair by pairing integers with strings. The class type retains the same name as the original version.

template<>classKeyValuePair<int,std::string>{};

The next is an example of partial specialization of KeyValuePair with the same name as the original version and one specialized template parameter.

template<typenameKey>classKeyValuePair<Key,std::string>{};

The next example class KeyStringPair is derived from the original KeyValuePair with a new name, and defines a partial template specialization. In contrast to the explicit specialization above, only the Value template parameter of the superclass is specialized, while the Key template parameter remains generic.

template<typenameKey>classKeyStringPair:publicKeyValuePair<Key,std::string>{};

It does not matter which template parameters are specialized and which remain generic. For instance, the following is also a valid example of a partial specialization of the original KeyValuePair class.

template<typenameValue>classIntegerValuePair:publicKeyValuePair<int,Value>{};

Caveats

C++ templates are not limited to classes - they can also be used to define function templates. Although function templates can be fully specialized, they cannot be partially specialized, irrespective of whether they are member function templates or non-member function templates. This can be beneficial to compiler writers, but affects the flexibility and granularity of what developers can do. [1] But, function templates can be overloaded, which gives nearly the same effect as what partial function template specialization would have. [2] The following examples are provided to illustrate these points.

// legal: base function templatetemplate<typenameReturnType,typenameArgumentType>ReturnTypeFoo(ArgumentTypearg);// legal: explicit/full function template specializationtemplate<>std::stringFoo<std::string,char>(chararg){return"Full";}// illegal: partial function template specialization of the return type//          function template partial specialization is not allowed// template <typename ArgumentType>// void Foo<void, ArgumentType>(ArgumentType arg);// legal: overloads the base template for a pointer argument typetemplate<typenameReturnType,typenameArgumentType>ReturnTypeFoo(ArgumentType*argPtr){return"PtrOverload";}// legal: base function name reused. Not considered an overload. ill-formed: non-overloadable declaration (see below)template<typenameArgumentType>std::stringFoo(ArgumentTypearg){return"Return1";}// legal: base function name reused. Not considered an overload. ill-formed: non-overloadable declaration (see below)template<typenameReturnType>ReturnTypeFoo(chararg){return"Return2";}

In the example listed above, note that while the last two definitions of the function Foo are legal C++, they are considered ill-formed according to the standard because they are non-overloadable declarations. [3] This is because the definition of function overloading only accounts for the function name, parameter type list and the enclosing namespace (if any). It does not account for the return type. [4] However, these functions can still be called by explicitly indicating the signature to the compiler, as demonstrated by the following program.

// note: to be compiled in conjunction with the definitions of Foo aboveintmain(intargc,char*argv[]){charc='c';std::stringr0,r1,r2,r3;// let the compiler resolve the callr0=Foo(c);// explicitly specify which function to callr1=Foo<std::string>(c);r2=Foo<std::string,char>(c);r3=Foo<std::string,char>(&c);// generate outputstd::cout<<r0<<" "<<r1<<" "<<r2<<" "<<r3<<std::endl;return0;}//expected output:Return1Return2FullPtrOverload

Related Research Articles

Templates are a feature of the C++ programming language that allows functions and classes to operate with generic types. This allows a function or class declaration to reference via a generic variable another different class without creating full declaration for each of these different classes.

Generic programming is a style of computer programming in which algorithms are written in terms of data types to-be-specified-later that are then instantiated when needed for specific types provided as parameters. This approach, pioneered by the ML programming language in 1973, permits writing common functions or types that differ only in the set of types on which they operate when used, thus reducing duplicate code.

Template metaprogramming (TMP) is a metaprogramming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled. The output of these templates can include compile-time constants, data structures, and complete functions. The use of templates can be thought of as compile-time polymorphism. The technique is used by a number of languages, the best-known being C++, but also Curl, D, Nim, and XL.

<span class="mw-page-title-main">D (programming language)</span> Multi-paradigm system programming language

D, also known as dlang, is a multi-paradigm system programming language created by Walter Bright at Digital Mars and released in 2001. Andrei Alexandrescu joined the design and development effort in 2007. Though it originated as a re-engineering of C++, D is now a very different language drawing inspiration from other high-level programming languages, notably Java, Python, Ruby, C#, and Eiffel.

In mathematics and computer science, a higher-order function (HOF) is a function that does at least one of the following:

In computer science, a type signature or type annotation defines the inputs and outputs of a function, subroutine or method. A type signature includes the number, types, and order of the function's arguments. One important use of a type signature is for function overload resolution, where one particular definition of a function to be called is selected among many overloaded forms.

In computer programming, a default argument is an argument to a function that a programmer is not required to specify. In most programming languages, functions may take one or more arguments. Usually, each argument must be specified in full. Later languages allow the programmer to specify default arguments that always have a value, even if one is not specified when calling the function.

In compiler construction, name mangling is a technique used to solve various problems caused by the need to resolve unique names for programming entities in many modern programming languages.

In mathematics and in computer programming, a variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments. Support for variadic functions differs widely among programming languages.

In the C++ programming language, argument-dependent lookup (ADL), or argument-dependent name lookup, applies to the lookup of an unqualified function name depending on the types of the arguments given to the function call. This behavior is also known as Koenig lookup, as it is often attributed to Andrew Koenig, though he is not its inventor.

typedef is a reserved keyword in the programming languages C, C++, and Objective-C. It is used to create an additional name (alias) for another data type, but does not create a new type, except in the obscure case of a qualified typedef of an array type where the typedef qualifiers are transferred to the array element type. As such, it is often used to simplify the syntax of declaring complex data structures consisting of struct and union types, although it is also commonly used to provide specific descriptive type names for integer data types of varying sizes.

sizeof is a unary operator in the programming languages C and C++. It generates the storage size of an expression or a data type, measured in the number of char-sized units. Consequently, the construct sizeof (char) is guaranteed to be 1. The actual number of bits of type char is specified by the preprocessor macro CHAR_BIT, defined in the standard include file limits.h. On most modern computing platforms this is eight bits. The result of sizeof has an unsigned integer type that is usually denoted by size_t.

C++11 is a version of the ISO/IEC 14882 standard for the C++ programming language. C++11 replaced the prior version of the C++ standard, called C++03, and was later replaced by C++14. The name follows the tradition of naming language versions by the publication year of the specification, though it was formerly named C++0x because it was expected to be published before 2010.

Substitution failure is not an error (SFINAE) is a principle in C++ where an invalid substitution of template parameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.

In computing, compile-time function execution is the ability of a compiler, that would normally compile a function to machine code and execute it at run time, to execute the function at compile time. This is possible if the arguments to the function are known at compile time, and the function does not make any reference to or attempt to modify any global state.

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

In computer programming, variadic templates are templates that take a variable number of arguments.

Concepts are an extension to the templates feature provided by the C++ programming language. Concepts are named Boolean predicates on template parameters, evaluated at compile time. A concept may be associated with a template, in which case it serves as a constraint: it limits the set of arguments that are accepted as template parameters.

"typename" is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type. In the original C++ compilers before the first ISO standard was completed, the typename keyword was not part of the C++ language and Bjarne Stroustrup used the class keyword for template arguments instead. While typename is now the preferred keyword, older source code may still use the class keyword instead.

C++14 is a version of the ISO/IEC 14882 standard for the C++ programming language. It is intended to be a small extension over C++11, featuring mainly bug fixes and small improvements, and was replaced by C++17. Its approval was announced on August 18, 2014. C++14 was published as ISO/IEC 14882:2014 in December 2014.

References

  1. Alexandrescu, Andrei (1 February 2001). Modern C++ Design . Addison Wesley. p. 23. ISBN   0-201-70431-5.
  2. Sutter, Herb (July 2001). "Why Not Specialize Function Templates?". C/C++ Users Journal. 19 (7). Retrieved 7 December 2014.
  3. "ISO/IEC JTC1 SC22 WG21 N 3690: Programming Languages — C++" (PDF). ISO. 15 May 2013. p. 294. Retrieved 16 October 2016. 13.1 Overloadable declarations [over.load] Not all function declarations can be overloaded. Those that cannot be overloaded are specified here. A program is ill-formed if it contains two such non-overloadable declarations in the same scope.
  4. "ISO/IEC JTC1 SC22 WG21 N 3690: Programming Languages — C++" (PDF). ISO. 15 May 2013. pp. 294–296. Retrieved 16 October 2016. 13.1 Overloadable declarations [over.load]