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.
Related
I have a specialization of a class called graph which is enabled only if the input is a particular type. I am not able to define out of class definitions for the functions inside that class. This question os different from some other questions on stack overflow where sfinae happens on member function. Here I want enable if on the class and just define a normal member function for this class outside the class.
Note- There are multiple graph classes with different container types. This is an example of just one.
I want to be able to define graph_func outside this class
template<typename ContainerType,
std::enable_if<std::is_same<ContainerType, Eigen::MatrixXd>::value, int>::type = 0>
class graph
{
.
.
.
void graph_func() const;
}
I tried this and I get the error that it doesn't refer into any class
template <typename ContainerType>
void graph<ContainerType, std::enable_if<std::is_same<Graph, Eigen::MatrixXd>::value, int>::type>::graph_func() const
{
// definition
}
Notice that std::enable_if<..., int>::type in your parameter list is an non-type template argument:
template<typename ContainerType,
typename std::enable_if<std::is_same<ContainerType, Eigen::MatrixXd>::value, int>::type = 0>
class graph
{
void graph_func() const;
};
You need to pass the value of that type (In here we just named it _) to the parameter list:
template <typename ContainerType,
typename std::enable_if<std::is_same<ContainerType, Eigen::MatrixXd>::value, int>::type _>
void graph<ContainerType, _>::graph_func() const
{
// definition
}
See live demo.
Is this legal C++?
template <typename T, template <typename T> class>
struct S { };
Clang (3.7.1) rejects it, complaining the second T shadows the first T. GCC seems not to care about it and I think that's reasonable. I think it is only the number of parameters that matters in a template template parameter.
http://goo.gl/51bHVG (gcc.godbolt.org)
No. [temp.local]/6:
A template-parameter shall not be redeclared within its scope
(including nested scopes).
While the right answer exists, it toke some time for myself to understand, and I just wanted to add an example:
template <class Key, class T>
class MyData {
public:
// ...
template <class Key, class T>
inline static MyData<Key, T> *get(MyMap<Key, T> *ptr)
{
return NULL: // Logic here...
}
// ...
}
As "Template-parameters shall not be re-declared within its scope (including nested scopes)",
above get(..) method should be changed and use other names, like:
template <class KeyType, class Type>
inline static MyData<KeyType, Type> *get(MyMap<KeyType, Type> *ptr)
{
return NULL: // Logic here...
}
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.
There are a few questions already similar to this already on stack overflow, but nothing that seemd to directly answer the question I have. I do apologise if I am reposting.
I'd like to overload a few methods of a templated class (with 2 template parameters) with a partial template specialisation of those methods. I haven't been able to figure out the correct syntax, and am starting to think that it's not possible. I thought I'd post here to see if I can get confirmation.
Example code to follow:
template <typename T, typename U>
class Test
{
public:
void Set( T t, U u );
T m_T;
U m_U;
};
// Fully templated method that should be used most of the time
template <typename T, typename U>
inline void Test<T,U>::Set( T t, U u )
{
m_T=t;
m_U=u;
}
// Partial specialisation that should only be used when U is a float.
// This generates compile errors
template <typename T>
inline void Test<T,float>::Set( T t, float u )
{
m_T=t;
m_U=u+0.5f;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test<int, int> testOne;
int a = 1;
testOne.Set( a, a );
Test<int, float> testTwo;
float f = 1.f;
testTwo.Set( a, f );
}
I know that I could write a partial specialisation of the entire class, but that kinda sucks. Is something like this possible?
(I'm using VS2008)
Edit: Here is the compile error
error C2244: 'Test::Set' : unable to match function definition to an existing declaration
Thanks :)
You cannot partially specialize a member function without defining partial specialization of the class template itself. Note that partial specialization of a template is STILL a template, hence when the compiler sees Test<T, float>, it expects a partial specialization of the class template.
--
$14.5.4.3/1 from the C++ Standard (2003) says,
The template parameter list of a
member of a class template partial
specialization shall match the
template parameter list of the class
template partial specialization. The
template argument list of a member of
a class template partial
specialization shall match the
template argument list of the class
template partial specialization. A
class template specialization is a
distinct template. The members of the
class template partial specialization
are unrelated to the members of the
primary template. Class template
partial specialization members that
are used in a way that requires a
definition shall be defined; the
definitions of members of the primary
template are never used as definitions
for members of a class template
partial specialization. An explicit
specialization of a member of a class
template partial specialization is
declared in the same way as an
explicit specialization of the primary
template.
Then the Standard itself gives this example,
// primary template
template<class T, int I> struct A {
void f();
};
template<class T, int I> void A<T,I>::f() { }
// class template partial specialization
template<class T> struct A<T,2> {
void f();
void g();
void h();
};
// member of class template partial specialization
template<class T> void A<T,2>::g() { }
I hope the quotation from the Standard along with the example answers your question well.
The particular problem you're sketching is easy:
template< class T >
inline T foo( T const& v ) { return v; }
template<>
float foo( float const& v ) { return v+0.5; }
Then call foo from your Test::Set implementation.
If you want the full generality, then similarly use a helper class with static helper member functions, and partially specialize that helper class.
Cheers & hth.,
There's also another solution to the partial specialization problem, if you don't want to introduce additional functions, methods or classes to your code.
#include <type_traits>
template <typename T1, typename T2>
class C
{
void f(T1 t1);
}
template <typename T1, typename T2>
void C<T1, T2>::f(T1 t1)
{
if (std::is_same<T2, float>::value)
// Do sth
else
// Do sth
}
// 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.