C++ templates - implementing outside the class - c++

Consider the following decleration
template<class T, int N>
class Stack
{
public:
Stack() : T[N]{} {};
class iterator;
iterator insert(iterator it, const T &v);
private:
T[N];
};
template<class T, int N>
class Stack<T,N>::iterator
{
...
};
I want to implement Stack::insert outside the class, so I tried the following
template<class T, int N>
Stack::iterator Stack<T, N>::insert(Stack::iterator p, const T &v)
{
...
}
Now I get the following error
'Stack' is not a class, namespace, or enumeration
I tried to change to the following
template<class T, int N>
Stack<T, N>::iterator Stack<T, N>::insert(Stack::iterator p, const T &v)
{
...
}
and now the error changed to
Missing 'typename' prior to dependent type name 'Stack<T, N>::iterator'
I don't understand why I get this error and how to fix it, hope that someone can help

I am surprised that you are getting the error you said because you have a very obvious syntax error in the constructor in data member:
Stack() : T[N]{} {}; // T[N] isn't valid!
T[N]; // same!
If T = int, the above would translate to int[4] resulting in the error. What you probably want is:
Stack() : arr{} {}
T arr[N];
Assuming this is fixed, we finally get to the error:
Missing 'typename' prior to dependent type name 'Stack<T, N>::iterator'
What this is saying is that iterator is a type and you can't directly access it using :: operator. You have to write typename before Stack<T, N>::iterator so that the compiler knows you want to access the subtype inside Stack. Read the answerWhere and why do I have to put the “template” and “typename” keywords? for more details.
To fix this, change the function to:
template<class T, int N>
typename Stack<T, N>::iterator Stack<T, N>::insert(typename Stack::iterator p, const T &v)
//^^typename here ^^ and here
{
...
}
As you can probably feel that typing so much is quite hectic. Hence auto keyword was introduced to save the programmer from typing these out everytime he wants to use it:
Stack<int,4>::iterator i = s.insert(it, 3); // imagine typing this everytime
//use auto
auto it = s.insert(iterator, 3); //good

Related

Trouble with storing a type tag when implementing an std::variant-like class

My aim is to write std::variant, may be not full blown, but at least with fully working constructor/destructor pair and std::get<>() function.
I tried to reserve a memory using char array. The size of it is determined by the biggest type, which is found by using find_biggest_size<>() function. The constructor uses static assert, because it performs check if the type is in the list of specified types. For now, the constructor and in place constructor works.
template <typename ... alternatives>
class variant
{
char object[find_biggest_size<alternatives...>::value];
public:
template <typename T>
variant(T&& other)
{
static_assert(is_present<T, alternatives...>::value, "type is not in range");
new ((T*)&object[0]) T(std::forward<T>(other));
}
template <typename T, typename ... ArgTypes>
variant(in_place_t<T>, ArgTypes&& ... args)
{
static_assert(is_present<T, alternatives...>::value, "type is not in range");
new ((T*)&object[0]) T(std::forward<ArgTypes>(args)...);
}
~variant()
{
// what to do here?
}
};
Then I've stumbled upon a problem. I don't know what destructor to execute when the object dies. On top of that, it is impossible to access the underlying object, since I can't specialize std::get<>() to get the right type.
My question is: how to store the type after the creation of the object? Is it the right approach? If not, what should I use?
EDIT:
I tried to apply the comments. The problem is that the index of the type that is currently alive can't be constexpr, thus I can't extract the needed type from type list and invoke appropriate destructor.
~variant()
{
using T = typename extract<index, alternatives...>::type;
(T*)&object[0]->~T();
}
EDIT:
I've made a baseline implementation. It works, but has lots of missing features. You can find it here. I would be glad to receive a review, but please first read how do I write a good answer?.
How I'd probably start:
#include <iostream>
#include <utility>
#include <array>
template<class...Types>
struct variant
{
variant() {}
~variant()
{
if (type_ >= 0)
{
invoke_destructor(type_, reinterpret_cast<char*>(std::addressof(storage_)));
}
}
template<class T> static void invoke_destructor_impl(char* object)
{
auto pt = reinterpret_cast<T*>(object);
pt->~T();
}
static void invoke_destructor(int type, char* address)
{
static const std::array<void (*)(char*), sizeof...(Types)> destructors
{
std::addressof(invoke_destructor_impl<Types>)...
};
destructors[type](address);
}
std::aligned_union_t<0, Types...> storage_;
int type_ = -1;
};
int main()
{
variant<int, std::string> v;
}
First of all, you need to know which object is currently in the variant. If you want to get a type from it, that is not currently in it, you must throw an exception.
For the storage I use a union (as I do here to make it constexpr); you can't use the placement new operator as a constexpr so I think the union is the only actual way to do that (which means the only one I came up with). Mind you: you still need to explicitly call the destructor. Which yields the strange workaround I have, because a type used in a constexpr must be trivially destructible.
Now: you can implement a class similar to find_biggest_size which gives you the type from an int as a template parameter. I.e. something like that (incomplete example) :
template<int idx, typename ...Args>
struct get_type;
template<int idx, typename First, typename ...Rest>
struct get_type<idx, First, Rest...>
{
using type = typename get_type<idx-1, Rest>::type;
};
template<typename First, typename ...Rest>
struct get_type<0, First, Rest...>
{
using type = First;
};
//plus specialization without Rest
And then you can implement the get function:
template<int i, typename ...Args>
auto get(variant<Args...> & v) -> typename get_type<i, Args...>::type
{ /* however you do that */ }
I hope that helps.

enable class's member depending on template

I already know that you can enable (or not) a class's method using std::enable_if
for exemple:
template<size_t D, size_t E>
class Field
{
...
size_t offset(const std::array<float,D>& p) const
{
...
}
template<typename TT = size_t>
typename std::enable_if<D!=E, TT>::type
offset(const std::array<float,E>& p) const
{
return offset(_projection(p));
}
...
};
This helps not being able to call function that are invalid in a specific case as well as removing overloading errors ... which, to me, is very nice !
I'd like to go further and make some of my class's members being present only if the are needed. That way I would get an error if I try to use an objected which would have otherwise not been initiated
I tried to do
template<size_t D, size_t E>
class Field
{
...
template<typename TT = projectionFunc>
typename std::enable_if<D!=E, TT>::type _projection;
}
But the compiler tells me :
erreur: data member ‘_projection’ cannot be a member template
Is there any way to achieve what I want ?
Hold the data members in a separate class that you can then specialize as needed.
template<size_t D, size_t E>
class Field {
template<size_t, size_t> struct Field_Members {
int _projection;
};
template<size_t V> struct Field_Members<V, V> { };
Field_Members<D, E> m;
};
and then use m._projection etc.
Field_Members doesn't have to be a nested class template; you can move it outside if desired. It is also possible to have Field inherit from it, but then it'd be a dependent base, and you'd have to write this->_projection, so it doesn't save much typing.
AFAIK, this is not possible with a simple SFINAE inside the class template. You can, of course, have the type of the member dependent on a compile-time condition, i.e. via std::conditional, but not eliminate the member entirely.
What you can do, of course, is use another class template, such as
template<bool Condition, typename T> struct Has { T value; };
template<typename T> struct Has<false,T> {};
and declare a member (or base) of this type and access the object via Has<>::value:
typename<bool Condition>
class foo
{
Has<Condition, double> x; // use x.value (only if Condition==true)
};

How do I define a static array to member functions of a templated class?

I want to do the following :-
#include <iostream>
template <typename I>
class A {
public:
I member_;
void f() {}
void g() {}
typedef void (A::*fptr) ();
static const fptr arr[];
};
template <typename I>
A<I>::fptr A<I>::arr[] = {
&A<I>::f,
&A<I>::g
};
How do I do this?
I get the following errors :-
g++ memeber_func_ptr_array.cpp
memeber_func_ptr_array.cpp:14:1: error: need ‘typename’ before ‘A<I>::fptr’ because ‘A<I>’ is a dependent scope
memeber_func_ptr_array.cpp:17:2: error: expected unqualified-id before ‘;’ token
Two things.
fptr is a dependent type so you need typename:
template <typename I>
const typename A<I>::fptr A<I>::arr[2] = { // also note the 2 and the const
&A<I>::f,
&A<I>::g
};
And as jrok noted in the comments, your declaration is const so the definition must be const as well.
Client code (files that just include the header) needs to know how big the array is so you need the actual size of the array in the declaration:
static const fptr arr[2]; // include size
You can only use the automatic deduction of the size of the array when the array is declared and initialised in the same place.
You need to add const typename before A<I>::fptr. The typename is there to tell the compiler that fptr is a type within A<I>.
You might want to look at C++ Templates: The Complete Guide by Vandevoorde and Josuttis for more information.
Use typename as:
template <typename I>
typename A<I>::fptr A<I>::arr[] = { &A<I>::f, &A<I>::g };
//^^^^^^^^note this
It is because fptr is a dependent type.

Variadic Template Template

I am trying to create a base class that is a wrapper around std::array that overloads a bunch of common arithmetic operators. The end result will be sort of like std::valarray, but with static size. I'm doing this because I am creating a whole host of child classes for my library that end up replicating this functionality. For example, I need to create a MyPixel class and a MyPoint class, both of which are essentially just statically sized arrays that I can perform arithmetic on.
My solution is to create a StaticValArray base class from which MyPoint and MyPixel can derive. However to disallow users from adding a MyPoint to a MyPixel, I'm using the CRTP pattern as such:
template<class T1, class T2>
struct promote
{
typedef T1 type; // Assume there is a useful type promotion mechanism here
};
template<class T, size_t S, template<typename... A> class ChildClass>
class StaticValArray : public std::array<T,S>
{
public:
// Assume there are some conversion, etc. constructors here...
template<class U>
StaticValArray<typename promote<T,U>::type,S,ChildClass> operator+
(StaticValArray<U,S,ChildClass> const & rhs)
{
StaticValArray<typename promote<T,U>::type,S,ChildClass> ret = *this;
std::transform(this->begin(), this->end(),
rhs.begin(), ret.begin(), std::plus<typename promote<T,U>::type>());
return ret;
}
// More operators....
};
This is pretty cool, because the ChildClass can have any arbitrary class template parameters, and this thing will work. For example:
template<class T, class U>
class MyClassTwoTypes : public StaticValArray<T,3,MyClassTwoTypes>
{ };
template<class T, class U>
class MyClassTwoTypes2 : public StaticValArray<T,3,MyClassTwoTypes2>
{ };
int main()
{
MyClassTwoTypes<int, float> p;
MyClassTwoTypes<double, char> q;
auto z = p + q;
MyClassTwoTypes2<double, char> r;
// r += q; // <-- Great! This correctly won't compile
return 0;
}
My problem is this: I would like to stuff some ChildClass into the CRTP bit of StaticValArray that doesn't necessarily have just classes as its template parameters. For example, consider this N-Dimensional Point class:
template<class T, size_t S>
class MyPointND : public StaticValArray<T,S,MyPointND>
{ };
This unfortunately won't compile, because size_t is not a typename - I get the compiler error:
type/value mismatch at argument 3 in template parameter list for ‘template<class T, long unsigned int S, template<class ... A> class ChildClass> class StaticValArray’
test.C:36:54: error: expected a template of type ‘template<class ... A> class ChildClass’, got ‘template<class T, long unsigned int S> class MyPointND’
Is there any way to create a variadic template template parameter pack that can be absolutely anything (typenames, ints, size_t's, doubles, whatever?) because in the end I really don't care what the type is in there. Note that I can't just fully specify ChildClass (e.g. class MyPointND: public StaticValArray<T,S,MyPointND<T,S>>) because this would break my type promotion mechanism.
What if, in place of the size_t, you used an std::integral_constant? You would embed the numerical value of the size of your array in it, and you could use it as a type.
EDIT
In order to reduce the verbosity, you could define your own integral constant class, something like:
template <std::size_t N>
struct size_ : std::integral_constant<std::size_t,N> {};
Then you could use it like this:
MyPointND<int,size_<3>> x;
What you need to do is have a traits class, specialized for each type containing whatever you need for type promotion, and then pass in the complete type to the StaticValArray.
Moreover, with decltype, you shouldn't need anything like this- decltype will tell you what you get by adding a float and an int.
template<class U>
StaticValArray<decltype(*(T*)nullptr + *(U*)nullptr),S,ChildClass> operator+
(StaticValArray<U,S,ChildClass> const & rhs)
{
StaticValArray<decltype(*(T*)nullptr + *(U*)nullptr),S,ChildClass> ret = *this;
std::transform(this->begin(), this->end(),
rhs.begin(), ret.begin(), std::plus<decltype(*(T*)nullptr + *(U*)nullptr)>());
return ret;
}

Typedef inside template class doesn't work

I have a problem with the following code:
template <typename U>
class lamePtr
{
public:
typedef U* ptr;
};
template <typename U>
class smarterPointer
{
public:
void funFun()
{
typedef lamePtr<U> someType;
someType::ptr query;
}
};
As you see, I have a typedef inside lamePtr. Inside smarterPointer class I have a function funFun(). What am I trying to do is to make another typedef someType. Till that line, everything works fine until we get to the line with someType::ptr query.
What I want here to happen is that "query" will become lamePtr< U >::ptr (a simple value, not a typedef ;). However, I get compilation errors (with gcc 4.4.3):
temp.cpp: In member function ‘void smarterPointer&ltU>::funFun()’:
temp.cpp:15: error: expected ‘;’ before ‘query’
What am I doing wrong here?
someType, as lamePtr<U> is a "dependant name". It depends on what U is as to whether or not there is a member ptr and, if so, what kind of "thing" that member is.
Of course, you know that for all T, lamePtr<T>::ptr is a type, but at this stage of compilation the parser does not know that.
Use the typename keyword to hint to the parser that it's a type. The rest will be resolved later in the compilation process. Just a little C++ quirk.
template <typename U>
class lamePtr
{
public:
typedef U* ptr;
};
template <typename U>
class smarterPointer
{
public:
void funFun()
{
typedef lamePtr<U> someType;
typename someType::ptr query;
}
};
You need the typename keyword to signify that someType::ptr is a type.
typename someType::ptr query;
See Officially, what is typename for? for detail.