What is wrong with this code:
Header:
#include <map>
using namespace std;
template<class T>
class ValueCollection
{
public:
ValueCollection(void);
int getValueCount(void);
map<string, T> Values;
};
Implementation:
#include "ValueCollection.h"
ValueCollection<class T>::ValueCollection(void)
{
}
int ValueCollection<class T>::getValueCount(void)
{
return Values.size();
}
Test:
#include "ValueCollection.h"
TEST(ValueCollection_TestCases, Default_Constructor_MapIsEmpty)
{
ValueCollection<int>* target = new ValueCollection<int>;
int expected = 0;
int actual = target->getValueCount();
ASSERT_EQ(expected, actual);
}
This is the error:
Error 1 error C2079: 'std::_Pair_base<_Ty1,_Ty2>::second' uses undefined class 'T' c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility 167 1 Refactor01
A couple of problems.
Your most immediate compiler error is caused by incorrect syntax in the implementation of the class template member functions. You must preface definition of a class template member with the template keyword. To wit:
template<class T> ValueCollection<T>::ValueCollection(void)
{
}
template<class T> int ValueCollection<T>::getValueCount(void)
{
return Values.size();
}
There's another problem too, which will only become apparent later as your program grows. You can't define template functions or classes in one Translation Unit and use them in antoher. The compiler must have the complete definition available in each translation unit.
Typically, the way this is accomplished is by defining template functions directly in the header file, right where they are declared. In your case:
template<class T>
class ValueCollection
{
public:
ValueCollection(void)
{
}
int getValueCount(void)
{
return Values.size();
}
map<string, T> Values;
};
That's just one way to accomplish this -- there are others. Another way is to use the so-called "inclusion method":
ValueCollection.h
template<class T>
class ValueCollection
{
public:
ValueCollection(void);
int getValueCount(void);
map<string, T> Values;
};
#include "ValueCollection.hpp:
ValueCollection.hpp
template<class T> ValueCollection<T>::ValueCollection(void)
{
}
template<class T> int ValueCollection<class T>::getValueCount(void)
{
return Values.size();
}
Yet another method would be to supply a new definition for each translation unit that wants to use the templates, but this would be highly unusual. (In fact, I have never done this in my 15 years of C++ programming)
implementation should read:
#include "ValueCollection.h"
template <class T>
ValueCollection<T>::ValueCollection(void)
{
}
template <class T>
int ValueCollection<T>::getValueCount(void)
{
return Values.size();
}
You require the template <class T> before every method in your implementation file too.
Related
I have used the std::enable_if metafunction in my class template to specify that it is only allowed to generate classes for variables that have GameCard as a base class. This works fine on its own when I implement the functions inline. However, if I want to implement the template functions outside the header body I run into the issue that I can't figure out how to correctly specify the function that I want to implement.
Cut down example code:
#include <string>
#include <memory>
#include <vector>
struct GameCard {};
template<class T, class = std::enable_if_t<std::is_base_of<GameCard, T>::value>>
struct CardStack {
std::vector<T> cards;
bool Test();
};
My IDE generates this as the function specification:
template<class T, class>
bool CardStack<T, <unnamed>>::Test() {
return false;
}
This is obviously wrong since I'm getting compiler errors. But I don't have a clue on how to do it right. Do any of you know how to do this right?
Out of class definition should be:
template<class T, class Enabler>
bool CardStack<T, Enabler>::Test() {
return false;
}
But currently, you class might be hijacked:
Whereas CardStack<int> or CardStack<int, void> won't compile thanks to SFINAE,
CardStack<int, char> would be "valid" (risk to not compile because of hard error produced by int in CardStack implementation).
static_assert seems enough in your case:
template<class T>
struct CardStack {
static_assert(std::is_base_of<GameCard, T>::value);
std::vector<T> cards;
bool Test();
};
With simpler out of class definition:
template<class T>
bool CardStack<T>::Test() {
return false;
}
The function member definition should be something like:
template <class T, class U>
bool CardStack<T, U>::Test() {
// body of function
}
Live example
The explanation is pretty straightforward, there is no back magic here.
Just follow the normal syntactic rules of C++.
The definition of your class is a template class with two template parameters:
template<class, class>
struct CardStack { /* ... */ };
T is the name of the first one.
On the other hand, the second does not have any type-name, but only a default type (= ...).
Default type (similarly to default arguments for functions) does not have to be specified in the definition.
Therefore, the each method definition should be in the form:
template <class T, class U>
bool CardStack<T, U>::MethodName() {}
I am trying to implement a template class that is stack. But I want to declare it before main. Can I do that? I know it will compile if you put the main after the template but is it possible to put the main first then the template?
#include <iostream>
//start declaration of template
template <class T>
class stack<T>;
//end declaration of template
int main() {
stack<char> s(5);
s.push('a');
s.push('b');
cout <<s.pop()<<endl;
stack<double> s1(10);
s1.push(3.2);
s1.push(0.5);
cout << s1.pop()<<endl;
return 0;
}
template <class T>
class stack {
T *s;
int size; //How many elements I can stole.
int top; //Where the index is available.
public:
stack(int sz) {
size = sz;
s = new T[sz];
top=-1;
}
void push(T e);
T pop() {
return s[top--];
}
};
template <class T>
void stack<T>::push(T e) {
s[++top] = e;
}
Error given:
1>.\classTemplPers.cpp(6) : error C2143: syntax error : missing ';' before '<'
1>.\classTemplPers.cpp(6) : error C2059: syntax error : '<'
For the record, doing this:
template <class T>
class stack;
doesn't work either. I see errors like this:
1>.\classTemplPers.cpp(10) : error C2079: 's' uses undefined class 'stack<T>'
The correct syntax for declaring a template is, as Quentin already pointed out:
template <class T>
class stack;
But it won't help you because:
is it possible to put the main first then the template?
You could do that only if you don't use the template in main.
But you do use the template, so no, you can't do that. The template must be defined before it can be instantiated. However, you may leave the definitions of the member functions after main if you wish.
You're almost there. The syntax is :
template <class T>
class stack;
But as any class declaration, it won't suffice if your use of it needs the full definition. Instanciating the template and using its member functions is one such case, so you're out of luck this time.
There are 2 different specialization template forms in c++
One is:
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
int main()
{
mytest<bool> mt;
mt.method(1);
system("pause");
return 0;
}
The other is:
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
int main()
{
mytest<bool> mt;
mt.method(1);
system("pause");
return 0;
}
They can also be compiled in VS2013. I notice that the second implementation of specialization template situation is just lack of template<>
I want to know what the difference is between the 2 forms above.
Visual C++ is wrong.
The standard is very clear about this.
First,
Members of an explicitly specialized class template are defined in the
same manner as members of normal classes, and not using the template<>
syntax.
Meaning that, for explicit specialization of a class template, the member definition strictly do not require template<>.
Example:
template<class T>
struct A {
};
template<>
struct A<int> {
void f(int);
};
// template<> not used for a member of an
// explicitly specialized class template
void A<int>::f(int) { / ... / }
And,
A member or a member template of a class template may be explicitly
specialized for a given implicit instantiation of the class template,
even if the member or member template is defined in the class template
definition. An explicit specialization of a member or member template
is specified using the syntax for explicit specialization.
Meaning that, for a template that is not "explicit specialized", you can specialize its member, with the template<> (syntax for explicit specialization)
Example,
template<class T>
struct A {
void f(T);
};
// specialization
template<>
void A<int>::f(int);
The above examples are directly copied out from standard. To summarize, if the class is already explicitly specialized, do not use template<>, else if the class relies on implicit instantiation, use template<>.
Your first example compiles fine in Clang, and your second example fails to compile in Clang, you will get an error:
error: template specialization requires 'template<>'
template <class T> class mycontainer { ... };
template <> class mycontainer <char> { ... };
The first line is the generic template, and the second one is the specialization.
When we declare specializations for a template class, we must also define all its members, even those identical to the generic template class, because there is no "inheritance" of members from the generic template to the specialization.
http://www.cplusplus.com/doc/tutorial/templates/
using namespace std;
#include <vector>
#include <string>
template <class T>
struct ValNode {
string id;
T value;
};
class ValTable {
public:
ValTable();
template <class T>
void add(string,T);
const bool find(string);
void remove(string);
private:
template<class T>
std::vector<ValNode<T>*> vals;
};
complier error:error: data member 'vals' cannot be a member template
i did try to use T* value in the struct, but i didnt work out.
I didnt use any of the functions in codes yet. was just trying to compling it into *.o file (with .cpp file also).
As the error says, variables (including data members) can't be templates; only classes and functions can be.
It looks like you want the table to be able to hold values of various different types, specified at run-time according to which types are passed to add(). For that, you need dynamic types, which aren't directly supported in C++. You might consider libraries like Boost.Any or Boost.Variant for that.
On the other hand, maybe you just want to store a single type in each table, and different types in different tables. In that case, the class itself will need to be a template:
template <typename T>
class ValTable {
public:
ValTable();
void add(string,T);
const bool find(string);
void remove(string);
private:
std::vector<ValNode<T>*> vals;
};
In C++ you can have template methods in a class, but not template data members.
For example:
template<typename T, int n>
struct FixedVector {
T x[n];
FixedVector() {
for (int i=0; i<n; i++) x[i] = 0;
}
template<typename C>
void copy(const C& container) {
if (container.size() != n) {
throw std::runtime_error("Wrong size");
}
int j = 0;
for (typename C::const_iterator i=container.begin(),
e=container.end();
i!=e;
++i)
{
x[j++] = *i;
}
}
};
With the above class you can declare FixedVector<int, 5> f and call f.copy(v) where v can be for example a vector or a list or anything that has size begin and end.
So FixedVector::copy is a template method and this means that the compiler will generate a different version of it for each different type you will pass to the function.
std::vector<double> y;
y.push_back(3.4); y.push_back(5.6); y.push_back(7.8);
std::list<unsigned char> z;
z.push_back('a'); z.push_back('b'); z.push_back('c');
FixedVector<int, 3> v;
v.copy(y); // This is ok
v.copy(z); // This is ok too
C++ doesn't allow template data members because this would imply a different class size depending on how many types you are using in a specific compilation unit and this doesn't go with the C++ compilation model of one-unit-at-a-time.
Adding methods is instead fine because it doesn't affect class size, and everything can be fixed at link time by avoiding pulling multiple copies of the same method from different compilation units.
You will have to declare ValTable as template
template <class T>
class ValTable{
public:
ValTable();
//template <class T>
void add(string,T);
const bool find(string);
void remove(string);
private:
//template<class T>
std::vector<ValNode<T>*> vals;
};
You won't be able to do that ValTable needs to be a template
You can have this :
template <class T> //Make the class as template
class ValTable {
public:
ValTable();
template <class X>
void add(string,X);
const bool find(string);
void remove(string);
private:
//template<class T>
std::vector<ValNode<T>*> vals;
};
You cannot have template member values: each translation unit could access different instantiations resulting in different ibject layouts. You'd need to factor out the type in some way.
The standard library does something along the lines of what you want for std::locale: each std::locale stores a collection of differently typed objects. It is soecial purpose and can't be used for your purpose directly.
The basic idea is to automatically map each type used to an int which is then used to map the type to an instance. The vals member would then be a function template looking up the correct instance. A rough outline could look like this:
int type_index_alloc() {
static std::atomic<int> current(0);
return ++current;
}
template <typename T>
int type_map() {
static int rc = type_index_alloc();
}
class container {
struct base { virtual ~base() {} };
template <typename T>
struct value: base { T v; };
std::map<int, std::shared_ptr<base>> vals_;
public:
T& vals() {
std::shared_ptr<base>& rc(vals_[type_map<T>()]);
if (!rc) {
rc = std::make_shared<value<T>>()); }
return static_cast<value<T>&>(*rc).v;
}
};
This a just trying to show how things are being set up: I currently don't have access to a compiler. Also, the code example just provides access to an object of type T but it could easily be changed to use a std::vector<T> instead.
I realize similar questions have been asked before, but I read a couple of those and still don't see where I'm going wrong. When I simply write my class without separating the prototype from the definition, everything works fine. The problem happens when I separate the prototype and definition as shown below:
template<class T> class VisitedSet {
public:
VisitedSet();
int getSize();
void addSolution(const T& soln);
void evaluate();
private:
vector<T> vec;
int iteration;
};
And as an example of a definition that gives me this error:
int VisitedSet::getSize() {
return vec.size();
I've never made a templated class before, so please pardon me if the problem here is trivial.
VisitedSet is a template, not a class, so you can’t use VisitedSet in a nested name specifier such as VisitedSet::getSize(). Just as you specified the declaration of class VisitedSet<T> for all class T, you must specify the definition of VisitedSet<T>::getSize() for all class T:
template<class T>
int VisitedSet<T>::getSize() {
// ^^^
return vec.size();
}
The name of a template can, however, be used as though it were a class within a template definition:
template<class T>
struct Example {
Example* parent;
T x, y;
};
In this case, Example is short for Example<T>.
You want this:
template <class T>
int VisitedSet<T>::getSize() {
return vec.size();
}
You have to state the template parameter in the definition as well
template<class T>
int VisitedSet<T>::getSize() {
return vec.size();
}
otherwise the compiler cannot match it to the declaration. For example, there could be specializations for some parameter types.
You need to let your compiler know that you are implementing a method in template function:
template<typename T>
int VisitedSet<T>::getSize() {
return vec.size();
}
Try putting
template <typename T>
above the implementation of VisitedSet::getSize() -- but beware that, in general, templated classes and functions should all be inlined. See the c++ faq here for more information.