Let's say I have a class template:
template <typename T>
class Array {
...
int length() const;
};
The definition of length would be
template <typename T>
int Array<T>::length() const
{
...
}
But why wouldn't it be? (I)
int Array<T>::length() const
{
...
}
Or maybe: (II)
template <typename T>
int Array::length() const
{
...
}
I guess (II) would be a function template. But actually I cannot understand the logic behind this syntax. Any rules to understand templates syntax?
int Array<T>::length() const
{
...
}
Illegal if:
you have not declared a class called T
you have not used typedef to give an existing type a new name - T
ex:
class T;
typedef double T;
using T = double;
template <typename T>
int Array::length() const
{
...
}
Illegal if:
you don't have a class called Array - different from template <class T> Array
Why it can't be (I) is easy: Without the template line, the compiler would have no choice but to interpret the < as a less-than operator, which would definitely not result in a useful function definition.
For (II) we need to consider how you would represent a function template of a class template. Say your class looked like this:
template <typename T>
class Array {
...
template <typename U>
int length() const;
};
Now you need to be able to explicitly specify which component takes which template parameter. Without explicitly specifying the <T> and <U> you would have at minimum a bunch of confusion about which parameter applies to which template. At worst it would be ambiguous and uncompilable.
template <typename T>
int Array::length() const
There may be partial specializations of a template. How is the compiler supposed to know whether this is a definition for the member of the primary template or a partial specialization?
int Array<T>::length() const
Every name in C++ must be declared. T, if to be used as a template parameter, must also be declared as one. You haven't, therefore the compiler will look for an earlier declaration and issue an error message as he finds none.
Related
I want to define function outside the template class as described below.
Already tried a lot of combinations for the second argument which is a template and takes default argument as well.
template <typename T>
class CustomAllocator
{
//My custom allocator
};
template <typename T, typename Allocator = CustomAllocator<T> >
class CustomContainer
{
void push_back();
};
/*I want to define push_back outside my class, tried everything.
Almost 4 hours spent through stackoverflow, fluentcpp and all sites*/
// What should be specified for Allocator here ?
template <typename T>
void CustomContainer<T,Allocator>::push_back(T value)
{
}
//OR
template <typename T>
void CustomContainer<T,CustomAllocator<> >::push_back(T value)
{
}
I expect it to be defined outside class
Actual getting compiler error, if it is simple type I could easily mention int,float etc. in the second argument.
Outside of your class definition, it will be unclear to a function what type Allocator is, so you have to redeclare it just like you redeclared T
template <class T, class Allocator>
void CustomContainer<T,Allocator>::push_back(T value)
{
// ...
}
(I'm assuming that DataType should be T)
Note that your declaration of push_back, in the class should match the definition:
template <typename T, typename Allocator = CustomAllocator<T> >
class CustomContainer
{
void push_back(T);
};
You may not use default template arguments for a member function of a template defined outside the template definition.
From the C++ 17 Standard (17.1 Template parameters)
... A default template-argument shall not be specified in the template-
parameter-lists of the definition of a member of a class
template that appears outside of the member’s class.
So just write
template <typename T, typename Allocator>
void CustomContainer<T, Allocator>::push_back( const T &value )
{
//...
}
Pay attention to the argument of the function. Your declaration of the function does not correspond to its definition.
I found a few questions that ask something similar but could not find a straight answer for my particular case.
The whole syntax for Templates is very confusing to me so I may just misunderstood something.
I have a class template that is supposed to accept every type.
Simple example:
template <class T>
class State {
public:
void set(T newState);
T get();
private:
T state;
};
template <class T>
void State<T>::set(T newState){
state = newState;
}
template <class T>
T State<T>::get(){
return state;
}
Now I would like to have a specialised template for a group of types that adds an additional function for these types. From what I found out so far I can utilize so called type_traits but how exactly they are used to achieve this is still a mystery to me.
F.e. this specialization for the int type but instead of writing this just for the int type I would also like to allow all other int and float variants. I found std::is_arithmetic but have no Idea how to utilize it to achieve this.
template <>
class State <int> {
public:
void set(int newState);
int get();
int multiplyState(int n);
private:
int state;
};
void State<int>::set(int newState){
state = newState;
}
int State<int>::get(){
return state;
}
int State<int>::multiplyState(int n){
return state*n;
}
You can use partial template specialization in combination with SFINAE to achieve this:
#include <type_traits>
template <class T, typename = void>
class State
{
T state;
public:
void set(T newState)
{
state = newState;
}
T get()
{
return state;
}
};
template <typename T>
class State<T, std::enable_if_t<std::is_arithmetic_v<T>>>
{
T state;
public:
void set(int newState)
{
state = newState;
}
int get()
{
return state;
}
int multiplyState(int n)
{
return state*n;
}
};
live example here
The trick here lies in the use of the second template parameter (which can be unnamed and is given a default argument). When you use a specialization of your class template, e.g., State<some_type>, the compiler has to figure out which of the templates should be used. To do so, it has to somehow compare the given template arguments with each template and decide which one is the best match.
The way this matching is actually done is by trying to deduce the arguments of each partial specialization from the given template arguments. For example, in the case of State<int>, the template arguments are going to be int and void (the latter is there because of the default argument for the second parameter of the primary template). We then try to deduce the arguments for our sole partial specialization
template <typename T>
class State<T, std::enable_if_t<std::is_arithmetic_v<T>>>;
from the template arguments int, void. Our partial specialization has a single parameter T, which can directly be deduced from the first template argument to be int. And with that, we're already done as we have deduced all parameters (there is only one here). Now we substitute the deduced parameters into the partial specialization: State<T, std::enable_if_t<std::is_arithmetic_v<T>>>. We end up with State<int, void>, which matches the list of initial arguments of int, void. Therefore, the partial template specialization applies.
Now, if, instead, we had written State<some_type>, where some_type is not an arithmetic type, then the process would be the same up to the point where we have successfully deduced the parameter for the partial specialization to be some_type. Again, we substitute the parameter back into the partial specialization State<T, std::enable_if_t<std::is_arithmetic_v<T>>>. However, std::is_arithmetic_v<some_type> will now be false, which will lead to std::enable_if_t<…> not being defined and substitution fails. Since substituion failure is not an error in this context, this simply means that the partial specialization is not an option here and the primary template will be used instead.
If there were multiple matching partial specializations, they then would have to be ranked to pick the best match. The actual process is quite complicated, but it generally boils down to picking the most concrete specialization.
While for a small example like this it's fine to specialize the whole class, in more complicated cases you might be interested in avoiding having to duplicate all the members just so you can add one member to the specialization. To that end, a common technique is to inherit the extra member functions from a public base class, and specialize only the base class to either have or not have the members. You have to use CRTP so that the base class member functions know how to access the derived class. This looks like:
// StateBase only contains the extra multiplyState member when State tells it to
// define it, based on T being an arithmetic type
template <class D, class T, bool has_multiply>
struct StateBase {};
template <class D, class T>
struct StateBase<D, T, true> {
T multiplyState(int n) {
return static_cast<D*>(this)->state * n;
}
};
template <class T>
class State : public StateBase<State<T>, T, std::is_arithmetic<T>::value> {
public:
// no need to duplicate these declarations and definitions
void set(T newState);
T get();
private:
// note that we write State::StateBase to force the injected-class-name to be found
friend struct State::StateBase;
T state;
};
Coliru link
If we have a standard class:
class Foo {
public:
int fooVar = 10;
int getFooVar();
}
The implementation for getFooVar() would be:
int Foo::getFooVar() {
return fooVar;
}
But in a templated class:
template <class T>
class Bar {
public:
int barVar = 10;
int getBarVar();
}
The implementation for getBarVar() must be:
template <class T>
int Bar<T>::getBarVar(){
return barVar();
}
Why must we have the template <class T> line before the function implementation of getBarVar and Bar<T>:: (as opposed to just Bar::), considering the fact that the function doesn't use any templated variables?
You need it because Bar is not a class, it's a template. Bar<T> is the class.
Bar itself is a template, as the other answers said.
But let's now assume that you don't need it, after all, you specified this, and I added another template argument:
template<typename T1, typename T2>
class Bar
{
void something();
};
Why:
template<typename T1, typename T2>
void Bar<T1, T2>::something(){}
And not:
void Bar::something(){}
What would happen if you wanted to specialize your implementation for one type T1, but not the other one? You would need to add that information. And that's where this template declaration comes into play and why you also need it for the general implementation (IMHO).
template<typename T>
void Bar<T, int>::something(){}
When you instantiate the class, the compiler checks if implementations are there. But at the time you write the code, the final type (i.e. the instantiated type) is not known.
Hence the compiler instantiates the definitions for you, and if the compiler should instantiate something it needs to be templated.
Any answer to this question boils down to "because the standard says so". However, instead of reciting standardese, let's examine what else is forbidden (because the errors help us understand what the language expects). The "single template" case is exhausted pretty quickly, so let's consider the following:
template<class T>
class A
{
template<class X>
void foo(X);
};
Maybe we can use a single template argument for both?
template<class U>
void A<U>::foo(U u)
{
return;
}
error: out-of-line definition of 'foo' does not match any declaration in 'A<T>'
No, we cannot. Well, maybe like this?
template<class U>
void A<U>::foo<U>(U u)
{
return;
}
error: cannot specialize a member of an unspecialized template
No. And this?
template<class U, class V>
void A<U>::foo(V u)
{
return;
}
error: too many template parameters in template redeclaration
How about using a default to emulate the matching?
template<class U>
template<class V = U>
void A<U>::foo(V u)
{
return;
}
error: cannot add a default template argument to the definition of a member of a class template
Clearly, the compiler is worried about matching the declaration. That's because the compiler doesn't match template definitions to specific calls (as one might be used to from a functional language) but to the template declaration. (Code so far here).
So on a basic level, the answer is "because the template definition must match the template declaration". This still leaves open the question "why can we not just omit the class template parameters then?" (as far as I can tell no ambiguity for the template can exist so repeating the template parameters does not help) though...
Consider a function template declaration
tempalte <typename T>
void foo();
now a definition
void foo() { std::cout << "Hello World"; }
is either a specialization of the above template or an overload. You have to pick either of the two. For example
#include <iostream>
template <typename T>
void foo();
void foo() { std::cout << "overload\n"; }
template <typename T>
void foo() { std::cout << "specialization\n"; }
int main() {
foo();
foo<int>();
}
Prints:
overload
specialization
The short answer to your question is: Thats how the rules are, though if you could ommit the template <typename T> from a definition of the template, a different way would be required to define an overload.
I would like to access a template parameter outside of a class. I usually do this as follows:
template <class T>
class A
{
typedef typename T T;
}
A<int>::T;
I would like to be able to do the same for non-type template parameters. This doesn't work:
template <int T>
class A
{
typedef typename T T;
}
A<3>::T;
I will clarify why I need this. I want to define a second class as follows:
template <class C>
class B
{
static int func() {return C::T;}
}
B<A<3> >::func();
What is the correct way to do this?
Thank you very much.
That's because T is not a type name and you cannot typedef it. It is an int value and, if you want to access it as a static member of the class, you need a static member int. Seems like what you really want is this:
template <int T>
class A
{
public:
static const int x = T;
};
doSomething(A<5>::x);
It's a value, and not a type, so perhaps:
template <int T>
class A
{
static const int param = T;
};
And then you can access it as A<42>::param. Not that it helps much, unless A is itself used as a template parameter somewhere else.
in the second case, T is not a type, it's an int value. Therefore you should define it as a const int or static const int value.
template <int T>
class A {
static const int T = T;
};
Note that it is customary to use T for types (in particular when the template is monadic, since there is no ambiguity on the type), and other names for constants, usually a more meaningful name, for instance SIZE or preferably Size (all caps symbols are best used for macros).
template <int Param>
class A {
static const int param = Param;
};
See other SO questions (like this one) for the use of static const values in the context of a template definition.
// InternalTemplate.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
template<class T>
struct LeftSide
{
static void insert(T*& newLink, T*& parent)
{
parent->getLeft() = newLink;
newLink->parent = newLink;
}
};
template<class T>
struct Link
{
T* parent_;
T* left_;
T* right_;
T*& getParent()const
{
return parent_;
}
template<class Side>
void plugIn(Link<T>*& newLink);
};
template<class T>
template<class Side>
void Link<T>::plugIn(Link<T>*& newLink)//<<-----why can't I type
//void Link<T>::plugIn<Side>(Link<T>*& newLink)<---<Side> next to plugIn
{
Side::insert(newLink,this);
}
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
I find it strange that I have to specify parameter for a class but cannot specify parameter for a function. Is there any reason why?
Function templates and class templates are complementary (I call them orthogonal, but you are free not to agree), and in template metaprogramming they actually serve orthogonal purposes.
Class templates allow you to pattern match on the template argument, ie. they provide partial specialization.
Function templates, to the contrary, don't allow partial specialization, but they allow template argument deduction, which means you don't have to write the template arguments explicitly (except for extra arguments, as in your example).
This, I think, explains the differences in syntax since they are different in what they can achieve. Moreover, function templates can have overloads, class templates cannot.
The way to combine both concepts is
1) to have helper class templates with static non template functions if you want partial specialization for function templates:
template <typename T>
struct doSomethingWithPointersHelper
{
static void act(T x) { ... }
};
template <typename T>
struct doSomethingWithPointersHelper<T*>
{
static void act(T* x) { ... }
};
// This acts as if we had a partial specialization
// for pointer types
template <typename T>
doSomethingWithPointers(T x)
{ return doSomethingWithPointersHelper<T>::act(x); }
There are other ways to achieve this in particular cases, but this approach always works.
2) To have helper template functions if you want to make use of argument deduction when constructing complex classes:
template <typename T, typename U>
struct MyComplexClass
{ ... };
template <typename T, typename U>
MyComplexClass<T, U> makeComplex(T t, U u)
{ return MyComplexClass<T, U>(t, u); }
in the standard library, you find make_pair, bind1st or mem_fun which make use of this technique.
$14/2 -
A template-declaration can appear only as a namespace scope or class scope declaration. In a function template declaration, the last component of the declarator-id shall be a template-name or operator-functionid (i.e., not a template-id). [ Note: in a class template declaration, if the class name is a simple-template-id, the declaration declares a class template partial specialization (14.5.5). —end note ]"
The standard forbids such a syntax explicitly. Refer this for more idea about template id / template name
You need to specialize on the Link struct in order to define it's template member function.
template<>
template<class Side>
void Link<int>::plugIn(Link<int>*& newLink)
{
Side::insert(newLink,this);
}
Gotta be honest, this makes my brain explode a little.