I'm currently working on a template graph class that utilizes two vectors to create an adjacency matrix. I can get this to work outside of the template class, but I can't seem to initialize the vectors.
Here is what I have:
#include <stdexcept>
#include <vector>
#include <list>
#include <string>
using namespace std;
namespace GraphNameSpace
{
template <class T>
class Graph
{
private:
vector<int> colOfRow(100);
vector<vector<int> > matrix(100);
};
}
I receive:
error: expected identifier before numeric constant
error: expected ‘,’ or ‘...’ before numeric constant
What is the reason that those won't initialize in the template class, and what would a solution to this be?
I know this may not be the most efficient way of doing it, but it's the way I understand best. If you would consider another way to be better, would you provide the way you would go about doing this?
It has nothing to do with template class. You could use member initializer list to initialize member variables:
namespace GraphNameSpace
{
template <class T>
class Graph
{
private:
vector<int> colOfRow;
vector<vector<int> > matrix;
public:
Graph() : colOfRow(100), matrix(100) {}
};
}
Or default member initializer (since c++11):
namespace GraphNameSpace
{
template <class T>
class Graph
{
private:
vector<int> colOfRow{100};
vector<vector<int> > matrix{100};
};
}
Related
I'm poking around in the myst of C++ instantiation / declaration order. Here's a fun bit I came across:
This compiles :
#include <cstddef>
#include <variant>
#include <array>
template <size_t V>
struct container
{
// THIS COMPILES
struct array;
using val = std::variant<std::monostate, int, array>;
// THIS DOESNT
// using val = std::variant<std::monostate, int, struct array>;
struct proxy : val
{
using val::variant;
};
struct array { };
};
int main()
{
container<10> ctr;
}
But when you opt for in-place declarations, it suddenly stops working (Demo):
#include <cstddef>
#include <variant>
#include <array>
template <size_t V>
struct container
{
// THIS COMPILES
// struct array;
// using val = std::variant<std::monostate, int, array>;
// THIS DOESNT
using val = std::variant<std::monostate, int, struct array>;
struct proxy : val
{
using val::variant;
};
struct array { };
};
int main()
{
container<10> ctr;
}
This is the error I get:
/opt/compiler-explorer/gcc-trunk-20220729/include/c++/13.0.0/type_traits:1012:52: error: static assertion failed: template argument must be a complete class or an unbounded array
1012 | static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
|
Can someone explain me exactly why this happens? What is the difference?
EDIT: You are allowed in certain circumstances to declare a type in a template argument list:
#include <cstddef>
#include <variant>
#include <array>
#include <cstdio>
void foo(std::initializer_list<struct array>);
struct array
{
array(int a) : a_{a} {}
void print() {
printf("%d\n", a_);
}
int a_;
};
void foo(std::initializer_list<struct array> init) {
for (auto a : init) {
a.print();
}
printf(".. it works\n");
}
int main()
{
foo({1,2,3});
}
I don't know when and where this applies though.
A declaration of the form
class-key attribute-specifier-seq(opt) identifier;
(where class-key means struct, class, or union), declares the identifier in the scope where the declaration appears ([dcl.type.elab]/2). That means in your first code snippet, array is forward declared as a member class of the container class template and you can later define it within the same scope.
When an elaborated-type-specifier such as struct array appears as a component of some larger declaration or expression, [dcl.type.elab]/3 applies. First, the compiler looks up the name array, ignoring anything that is not a type ([basic.lookup.elab]/1). If it doesn't find anything, then it forward-declares array in "the nearest enclosing namespace or block scope". Consequently, the struct array that you later define as a nested class is a different class, and the one you referred to as struct array earlier has no definition.
The title might seem a little confusing, so here is a more thorough explanation:
I have a templated class that has a vector as a member variable. The template argument is a struct (or class) that will have one certain variable. The type of this vector shall be derived from the template argument (from this one certain variable). The tricky part is that it shall be derived from a member variable of the template argument.
#include <vector>
#include <complex>
using namespace std;
struct thingA {
double variable;
//...
};
struct thingB {
complex<double> variable;
//...
};
template <class S>
class someClass {
vector< " type of S::variable " > history; // If S=thingA, make it a double, if S=tingB make it a complex<double>
}
// Usage:
someClass<thingA> myInstanceA; // (this instance should now have a vector<double>)
someClass<thingB> myInstanceB; // (this instance should now have a vector<complex<double>>)
You can get the type via decltype, if the names of data member are always the same:
template <class S>
class someClass {
vector< decltype(S::variable) > history; // if S=thingA, make it a double, if S=tingB make it a complex<double>
};
I would define the type in the structs and use it in the class:
#include <vector>
#include <complex>
using namespace std;
struct thingA {
using Type = double;
Type variable;
//...
};
struct thingB {
using Type = complex<double>;
Type varbiable;
//...
};
template <class S>
class someClass {
vector<typename S::Type> history; // if S=thingA, make it a double, if S=tingB make it a complex<double>
};
// usage:
someClass<thingA> myInstanceA; // (this instance should now have a vector<double>)
someClass<thingB> myInstanceB; // (this instance should now have a vector<complex<double>>)
https://godbolt.org/z/raE9hbnqW
That is also the way to go when the variables do not have the same name.
I am trying to inherit the std::vector class template into my membvec class template as public. And I want to use it as e.g. say membvec<float> mymemb(10) with the intention of creating my membvec variable mymemb containing 10 elements.
But I can't figure out how to write the templatised declaration of the public inheritance. What I am doing is the following, but all in vain.
template <typename T, template <typename T> class std::vector = std::vector<T>>
//error above: expected '>' before '::' token
class membvec: public std::vector<T>
{
const membvec<T> operator-() const; // sorry the previous version was a typo
//error above: wrong number of template arguments (1, should be 2)
...
};
I think you're looking for something like the below, but seriously don't do it. If you ever pass your class as its parent std::vector, there is no virtual interface to allow your class to provide any benefit whatsoever. And if you don't need to substitute for a std::vector then there's no need to inherit from it. Prefer free function algorithms or containing the std::vector as a member in your class instead.
#include <vector>
template <typename T>
class membvec: public std::vector<T>
{
// Don't need <T> in class scope, must return by value.
membvec operator+() const;
};
int main()
{
membvec<int> foo;
}
Perhaps you want something like this:
#include <vector>
template <typename T, template <typename T, class Allocator> class Vec = std::vector>
class membvec: public Vec<T, std::allocator<T>>
{
public:
// This is the signature in your question, but it's questionable.
const membvec<T, Vec> &operator+(int x) const
{
// You obviously want to change this.
return *this;
}
};
You can then use it regularly:
int main()
{
membvec<char> foo;
foo + 3;
}
I have a list as a private member of a class that has two template arguments: type for the data type of the list elements and size for the number of elements in the list. To this end, I want to use the list's fill constructor using my two template arguments. Here is my attempt:
#include <list>
template <typename type, unsigned int size>
class my_class {
private:
std::list<type> my_queue(size, 0);
// More code here...
};
My approach seems to follow the information and example provided here; but when I compile this, I get the following error.
error: 'size' is not a type
error: expected identifier before numeric constant
error: expected ',' or '...' before numeric constant
It seems as though it recognizes the declaration of the list by its default constructor instead of the fill constructor. Can anyone help me solve this?
Thank you!
Edit: here is my revised source with more detail. I am now having trouble with the public method. Note: this is my class's header file.
#include <list>
template <typename T, unsigned int N>
class my_class {
private:
std::list<T> my_queue;
public:
// Constructor
my_class() : my_queue(N, 0) { }
// Method
T some_function(T some_input);
// The source for this function exists in another file.
};
Edit 2: Final implementation... thank you, #billz!
#include <list>
template <typename T, unsigned int N>
class my_class {
private:
std::list<T> my_queue;
public:
// Constructor
my_class() : my_queue(N, 0) { }
// Method
T some_function(T some_input){
// Code here, which accesses my_queue
}
};
You could only initialize member variable in constructor before C++11, better use uppercase character as template argument:
template <typename T, unsigned int N>
class my_class {
public:
my_class() : my_queue(N, 0) { }
private:
std::list<T> my_queue;
// More code here...
};
Edit:
T some_function(T some_input); C++ only supports inclusive-module, you need to define some_function in the same file as my_class is declared.
I have a class that is a template, using the argument: template <class X>
Can I template this class to be of type std::pair < W, Z>? I am getting an unresolved external symbol error, and trying to track down the cause.
A little example of passing a pair into a template.
#include <iostream>
#include <vector>
template <typename T>
class C {
public:
void add(const T& val) { m_vec.push_back(val); }
private:
std::vector<T> m_vec;
};
int main()
{
C<std::pair<int, char> > pairC;
pairC.add(std::make_pair(5, 2));
}
would instantiate a template class taking a std::pair and holding it in a vector. Add inserts a pair made with make_pair into that vector.
Note that for older C++ compilers you need to add a space between the two right-chevrons to stop it from being seen as a right-shift operator.