C++ decltype in template inner class - c++

My problem is illustrated by the example below:
#include <vector>
template <class T>
class TestNest{
public:
std::vector<T> m_list;
class InsideNest{
const TestNest<T>* m_test;
decltype(m_test->m_list.begin()) m_iter;
public:
InsideNest(const TestNest<T>* source)
:m_test(source)
,m_iter(source->m_list.begin())
{}
};
};
int main(int argc, char *argv[])
{
TestNest<int> outside;
TestNest<int>::InsideNest inside(&outside);
}
the part that does not compile (at least not in MSVC2013) is decltype(m_test->m_list.begin()). Any idea how I can get around the problem?
EDIT: changed code to show main() and #include

To close the issue. This is a shortcoming of MSVC2013. It will resolve decltype() before "working out" the full type of members so inside decltype any access to methods is a compiler error.
Even using global template functions (e.g. decltype(std::begin(m_list))) won't work.
Other, more modern, compilers work.

Related

Instance of C++ template class as a member of another template class

Let's say I have following templated C++ class
#include <cstdint>
template <uint32_t NO_POINTS>
class A
{
public:
struct Point
{
float x;
float y;
};
A(const Point (&points)[NO_POINTS])
{
for (uint32_t point = 0; point < NO_POINTS; point++) {
table[point] = points[point];
}
}
private:
Point table[NO_POINTS];
};
and I would like to use an instance of this class as a private member of the following class:
#include "A.h"
template <uint32_t NO_LUT_POINTS>
class B
{
public:
B(A<NO_LUT_POINTS>::Point (&table)[NO_LUT_POINTS]) : lut(table){}
private:
A<NO_LUT_POINTS> lut;
};
#include "B.h"
int main(int argc, char** argv) {
B<4> foo({{1326.0, 25.0}, {1601.0, 30.0}, {1922.0, 35.0}, {2293.0, 40.0}});
return 0;
}
I have attempted to compile this code but the compiler reports following error
A<NO_LUT_POINTS>::Point is not a type. I don't understand what the reason for this error is. Can anybody explain to me why the compiler reports this error?
This is a common mistake with types nested in template classes. You need to add typename to tell the compiler that Point is a type.
...
public:
B(typename A<NO_LUT_POINTS>::Point const (&table)[NO_LUT_POINTS]) : lut(table){}
...
Beyond solving your problem, however, please notice that Point doesn't depend on the template parameters of A, so you should not nest it in that class. This would remove the necessity for adding typename.

Forward-declaring templates that need each other

A professor at uni wanted us to implement a stack using an std::vector, and to write an "unstacking" iterator for it (that is, an iterator which when iterated over pops the top of the stack).
Everything could have been fine until he also decided he wanted all of it to be generic, using templates and all. That's when hell began.
So the first thing I did was writing template<typename T> class VectorStack:
//file VectorStack.hpp
template <typename T>
class VectorStack
{
public:
VectorStack();
virtual size_t size();
virtual bool empty();
virtual void push(T obj);
virtual T pop();
private:
vector<T> _data;
};
Implementation may not be relevant here so I'll skip it. Don't hesitate to ask if you need it.
Then I had to write template<typename T> class VectorStackIterator...
In order for that iterator to unstack an instance of VectorStack, it must contain at least a pointer to that instance. So VectorStackIterator needs to know about VectorStack, which leads us to a first forward declaration.
But also, VectorStack has begin() and end() methods which are supposed to return a VectorStackIterator. So VectorStack also needs to know about VectorStackIterator, which leads us to a second forward declaration.
So I wrote my iterator in a separate file:
//file VectorStackIterator.hpp
template<typename T>
class VectorStack; //Forward declaration of the VectorStack
template<typename T>
class VectorStackIterator : public iterator<random_access_iterator_tag, VectorStack<T>>
{
public:
VectorStackIterator(size_t n, VectorStack<T>* instance);
T operator--();
bool operator==(VectorStackIterator other);
bool operator!=(VectorStackIterator other);
private:
VectorStackIterator();
T& operator=() {};
size_t _n;
VectorStack<T>* _instance;
};
...and updated my VectorStack to look like this:
//file VectorStack.hpp
template<typename T>
class VectorStackIterator; //Forward declaration of the iterator
template <typename T>
class VectorStack
{
public:
//...
VectorStackIterator<T> top();
VectorStackIterator<T> bottom();
//...
};
Again, implementation of the iterator may not be relevant.
At this point, I already had the compiler screaming because I was using incomplete types everywhere. So I tried out something else: I put the declarations of both the VectorStack and the VectorStackIterator at the beginning of the same file, and only then, I put the definitions of all of the methods. Here is what it looks like:
//file VectorStack.hpp
#ifndef VECTOR_STACK_HPP
#define VECTOR_STACK_HPP
#include <vector>
using std::vector;
#include <iterator>
using std::iterator;
#include <exception>
using std::out_of_range;
template <typename T>
class VectorStack;
//still had to forward-declare this because VectorStackIterator uses it in its own declaration.
//Class declaration (VectorStackIterator)
template<typename T>
class VectorStackIterator : public iterator<random_access_iterator_tag, VectorStack<T>>
{
public:
VectorStackIterator(size_t n, VectorStack<T>* instance);
T operator--();
bool operator==(VectorStackIterator other);
bool operator!=(VectorStackIterator other);
private:
VectorStackIterator();
T& operator=() {};
size_t _n;
VectorStack<T>* _instance;
};
//Class declaration (VectorStack)
template <typename T>
class VectorStack
{
public:
VectorStack();
virtual size_t size();
virtual bool empty();
virtual void push(T obj);
virtual T pop();
VectorStackIterator<T> top();
VectorStackIterator<T> bottom();
private:
vector<T> _data;
};
All of this is followed by the definition of every method declared above. I don't think that's where the error lies in, but please ask if you want me to provide it.
This is the closest attempt to a solution that I've come up with, but the compiler still complains about Incomplete types not allowed here when I declare a VectorStack<int> object in the main function:
#include "VectorStack.hpp"
int main(int argc, char** argv)
{
VectorStack<int> v; //Incomplete types not allowed here
v.push(0); //Incomplete types not allowed here
v.push(1); //Incomplete types not allowed here
v.push(2); //Incomplete types not allowed here
for (auto it = v.top(); it != v.bottom();) //Incomplete types not allowed here (x2)
{
cout << it-- << endl;
}
return 0;
}
If I try to forward-declare the iterator instead of the vector stack, then the vector stack is no longer incomplete, but the iterator is, and I get errors on the heading line of the for loop.
It looks like the compiler won't ever go beyond the forward declaration, to the actual definitions that make everything complete.
I'm running out of options, do you have any ideas?
It's a bit hard to follow your post. But in general, there are some things to keep in mind:
Class members stored by value require complete types to be available at the time that the containing class is declared, because the compiler needs to know how much memory the object should take.
Pointer and reference members do not need to be complete when declaring the containing class, because the size is always just the size of a pointer.
Complete types are always required as soon as you start to use the object in question, because the compiler needs to know what member variables and functions that type should contain.
If you ever get into a situation where you can't resolve "incomplete type" errors, double check your design to make sure that it makes sense; you don't want (for example) two types to circularly contain each other (by value, again references and pointers are fine).
That said, I think the standard way to handle this is:
class ClassB;
class ClassA {
ClassB* or ClassB&
}
class ClassB {
ClassA
}
ClassA::implementations // These two can happen in any order, since both ClassA and ClassB are complete at this point
ClassB::implementations
Since both of your classes are templated, the implementations need to be put in header files, so you may need to be careful with the way you structure your files to enforce the order in which these pieces will happen.

Error while inheriting std::vector

I am trying to define an inherited class from std::vector class. Below is the code
template<class t>
class Vector:vector<t>
{
public:
using vector<t>::vector;
};
int main(int argc, char *argv[])
{
Vector<int> v;
return 0;
}
And I am getting error like this:
"error: 'std::vector<t, std::allocator<_CharT> >::vector' names constructor"
So basically I would like to know why my program is failing and what all procedures to be overloaded in the my inherited class from parent std::vector class.
Thanks in advance.
I tried:
#include <vector>
template<class t>
class Vector: std::vector<t>
{
public:
using std::vector<t>::vector;
};
int main()
{
Vector<int> v;
return 0;
}
and it works fine on gcc 4.8. when passing the flag -std=c++11.
It sounds like your compiler cannot figure out what are you trying to accomplish with that using directive. Since inheriting constructors is a C++11 feature, I suggest you make sure that you are running your compiler in C++11 mode.

std::is_default_constructible<T> error, if constructor is private

I have following snippet
#include <type_traits>
#include <boost/type_traits.hpp>
class C { C() { } };
int main()
{
static_assert(!boost::has_trivial_default_constructor<C>::value, "Constructible");
static_assert(!std::is_default_constructible<C>::value, "Constructible");
}
Conditions are not equal, but first condition works fine and second construction give error, that constructor is private. Compiler gcc 4.7... So, is this gcc bug, or it's defined by standard?
http://liveworkspace.org/code/NDQyMD$5
OK. Since this conditions are really unequal - we can use something like this
#include <type_traits>
#include <boost/type_traits.hpp>
class C { private: C() noexcept(false) { } };
int main()
{
static_assert(!boost::has_nothrow_constructor<C>::value, "Constructible");
static_assert(!std::is_nothrow_constructible<C>::value, "Constructible");
}
http://liveworkspace.org/code/NDQyMD$24
Anyway, i know, that static_assert should not fails, since types are really not default constructible/not nothrow constructible. Question is: WHY there is compilation error, not by my static assert?
Looks like a compiler bug. Let's see the following example of SFINAE(similar implementation is used in g++'s type_traits header)
#include <type_traits>
class Private
{
Private()
{
}
};
class Delete
{
Delete() = delete;
};
struct is_default_constructible_impl
{
template<typename T, typename = decltype(T())>
static std::true_type test(int);
template<typename>
static std::false_type test(...);
};
template <class T>
struct is_default_constructible: decltype(is_default_constructible_impl::test<T>(0))
{
};
int main()
{
static_assert(is_default_constructible<Private>::value, "Private is not constructible");
static_assert(is_default_constructible<Delete>::value, "Delete is not constructible");
}
The second assert works as expected, we can't deduce Delete type, since the class has only one deleted constructor. But when compiler tries to deduce type of Private(), it gives error: Private::Private() is private. So, we have two classes with private constructor, but one of them gives error, and second - not. I think, that this behavior is wrong, but I can't find confirmation in the standard.
P.S. all off presented codes compiles by clang without any errors.

typename when defining map data that is a function pointer with a sprinkling of templates

This is a strange question because I already know the 'coding' answer. I just want to get a better understanding of why it is so. There are guru's here who have a knack of explaining these things better than the C++ standard :)
Below we have a means to define an abstract factory template that allocates objects based on a string as a key (it is a contrived example):-
#include <iostream>
#include <map>
#include <string>
using namespace std;
template <typename T, typename TProduct>
TProduct *MyFactoryConstructHelper(const T *t)
{
if (!t) return new T;
return new T(*static_cast<const T*>(t));
}
template <typename TProduct>
class AbstractFactory
{
public:
typedef TProduct *(*MyFactoryConstructor)(const void *);
typedef map<string, MyFactoryConstructor> MyFactoryConstructorMap;
static TProduct *Create(const string &iName)
{
MyFactoryConstructor ctr = mTypes[iName];
TProduct *result = NULL;
if(ctr) result = ctr(NULL);
return result;
}
template <typename T>
static bool Register(const string &iName) {
typedef TProduct*(*ConstructPtr)(const T*);
ConstructPtr cPtr = MyFactoryConstructHelper<T, TProduct>;
string name = iName;
mTypes.insert(pair<string,MyFactoryConstructor>(name, reinterpret_cast<MyFactoryConstructor>(cPtr)));
return(true);
}
protected:
AbstractFactory() {}
static MyFactoryConstructorMap mTypes;
};
template <typename TProduct>
map<string, /*typename*/ AbstractFactory<TProduct>::MyFactoryConstructor> AbstractFactory<TProduct>::mTypes;
Here is an example of how we use it: -
class MyProduct
{
public:
virtual ~MyProduct() {}
virtual void Iam() = 0;
};
class MyProductFactory : public AbstractFactory<MyProduct>
{
public:
};
class ProductA : public MyProduct
{
public:
void Iam() { cout << "ProductA" << endl; }
};
class ProductB : public MyProduct
{
public:
void Iam() { cout << "ProductB" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
MyProduct *prd;
MyProductFactory::Register<ProductA>("A");
MyProductFactory::Register<ProductB>("B");
prd = MyProductFactory::Create("A");
prd->Iam();
delete prd;
prd = MyProductFactory::Create("B");
prd->Iam();
delete prd;
return 0;
}
It will not compile as is, complaining that the map does not have a valid template type argument for the data type. But if you remove the comments around the 'typename' keyword in the static member definition, everything compiles and works fine... why?
and also, can I make this any better? :)
The standard tries to allow an implementation to parse and
detect as many errors in a template as possible when it reads
the template definition, before any instantiations. C++ is not
context independent, however, and it's very difficult, if not
impossible, to correctly parse statements if you don't know
which symbols are types and which are templates. If the symbol
is dependent (depends on the template parameters in some way),
you have to tell the compiler when it is a type or a template;
otherwise, the compiler must assume that it is something else.
In this case, you're telling the compiler that
AbstractFactory::MyFactoryConstructor names a type,
and not something else.
If, when the template is instantiated, and the compiler can see
to what the symbol is really bound, it turns out that you lied
(e.g. AbstractFactory::MyFactoryConstructor is in fact
an int), then the compiler will get mad at you.
Note too that the fact that the AbstractFactory was defined
before the definition requiring the typedef doesn't change
anything. There could always be an explicit specialization for
the type you're instantiating AbstractFactory on.
The simple reason is that even though you and I looking at the code know that AbstractFactory::MyFactoryConstructor is a type, the compiler doesn't -- or rather, is prohibited by the standard from knowing this. As far as it knows in the first pass of compilation, MyFactoryConstructor -- itself inside a template yet to be fully realized -- could be something else, like a static variable, which isn't allowed as the second template argument to the map, which requires a type. Supplying "typename" permits the compiler to treat it as a type as soon as it is first encountered.