I am a beginner in C++. What is the correct way to call a function that expects std::istream&?
Tried it with read(std::cin);, but I get an error from the compiler.
typedef double Element;
template<typename T>
std::list<T> read(std::istream& i) {
Element input;
std::list<Element> l;
while(i>>input) {
l.push_back(input);
}
return l;
}
This is not related to the std::istream& parameter.
The issue is that the function is a function template that requires an explicit template argument determining the type that is supposed to be read from the stream, e.g.:
read<int>(std::cin)
The error message from the compiler should be telling you something like that as well.
That aside, you are then not using T in the function. Probably you wanted to replace all uses of Element by T and remove the typedef.
you have just a small syntax error:
try this code :
typedef double Element;
class test{
public:
auto read(std::istream& i){
Element input;
std::list<Element> l;
while(i>>input){
l.push_back(input);
}
return l;
}
};
int main(){
test t;
t.read(std::cin);
return 0;
}
Related
I'm a newbie in c++ and I have this piece of code:
#include "passenger.h"
#include "plane_list.h"
int main(){
plane_list<T>::plane_list();
plane_list<T>::add();
}
and I don't understand nor can I seem to find an answer online why I get these errors:
error: ‘T’ was not declared in this scope
plane_list::plane_list();
error: template argument 1 is invalid
plane_list::plane_list();
error: invalid type in declaration before ‘;’ token
plane_list::plane_list();
error: ‘::add’ has not been declared
plane_list::add();
This is the header file:
template <class T> class plane_list{
friend class planes;
public:
plane_list();
~plane_list();
int search(const std::string &flight_code);
plane_list<T> del(const std::string &flight_code);
plane_list<T> add();
private:
T *element;
int length;
};
template <class T> plane_list<T>::plane_list(){
element = new T[100];
length=0;
}
template <class T> int plane_list<T>::search(const std::string &flight_code){
for(int i=0;i<length;i++)if(element[i]._flight_code==flight_code)return i;
return 0;
}
template <class T> plane_list<T> plane_list<T>::del(const std::string &flight_code){
if(search(flight_code)!=0){
for(int i=search(flight_code); i<length; i++)element[i-1]=element[i];
length--;
return *this;
}
else
std::cerr<<"Did not find flight"<<std::endl;
}
template <class T> plane_list<T> plane_list<T>::add(){
element[length]=planes::planes();
length++;
return *this;
}
Any help would be appreciated.
The issue is that there is no type T. I am assuming that plane_list is some template class like this:
template<typename T>
class plane_list{
//...
}
Here the typename T is a placeholder for some type that will be provided when you instantiate the class.
You are getting an error because you are trying to instantiate the plane_list with a type that does not exists.
To use your class correctly you need to change T to some other type:
//for example you could use an int
int main(){
plane_list<int>::plane_list();
plane_list<int>::add();
}
Without knowing the contents of plane_list.h I cannot infer what you are actually trying to do.
EDIT:
As suggested in the comments. You are using the incorrect syntax for instantiating and using your variable. The correct usage would be:
int main(int argc, char** argv){
//create a variable of type plane_list<int> names "list:
plane_list<int> list; //default constructor is called automatically
list.add(); ///call the member function "add"
}
Additionally your code has a memory leak, you allocate the array 'element' with dynamic storage by calling new in your constructor, but never call delete element anywhere which causes the leak. There are several ways to fix this:
Add a destructor and call delete element in it.
Use std::vector<T> if you need to resize the array.
Use std::unique_ptr<T> if you need a fixed length array of runtime determined length.
Don't use dynamic memory since you are allocating an array with compile time size.
I will not provide an example of each of these, but I would recommend reading up on memory management in C++.
Go through your header and be sure to correct the your function call syntax. There are a few places where you are using the same incorrect syntax within your class. For example:
template <class T> plane_list<T> plane_list<T>::add(){
//element[length]=planes::planes();
element[length]=planes{}; //default initialize a "planes" object
length++;
return *this;
}
I have the following case of a nested class:
class PS_OcTree {
public:
// stuff ...
private:
struct subdiv_criteria : public octree_type::subdiv_criteria {
PS_OcTree* tree;
subdiv_criteria(PS_OcTree* _tree) : tree(_tree) { }
virtual Element elementInfo(unsigned int const& elem, node const* n) override;
};
};
To implement this method in the .cpp file, I write
PS_OcTree::subdiv_criteria::Element
PS_OcTree::subdiv_criteria::elementInfo(
unsigned int const& poly_index, node const* n)
{
// implementation goes here
}
I'm fine with writing the full name of the method, but do I really also need to write the full name of the return type? Inside the parameter parentheses and the function body, I can access names of the subdiv_criteria class, but that doesn't seem to work for the return type.
Preferrably, I'd like to write something like
Element PS_OcTree::subdiv_criteria::elementInfo(
unsigned int const& poly_index, node const* n)
{
// implementation goes here
}
// or
auto PS_OcTree::subdiv_criteria::elementInfo(
unsigned int const& poly_index, node const* n)
{
// implementation goes here
}
At least something that doesn't require me to repeat PS_OcTree::subdiv_criteria in the return type. Is there something in C++11 that I can use? It should work with MSVC 2015 and Clang 5 as well.
Class-scope lookup applies to anything after the declarator-id (which is the name of the function being defined, i.e., PS_OcTree::subdiv_criteria::elementInfo), including a trailing return type. Hence,
auto PS_OcTree::subdiv_criteria::elementInfo(
unsigned int const& poly_index, node const* n) -> Element
{
}
I don't know what to do. I always get an error by using a simple class and a simple template function. I read all the other solutions but they didn't helped me.
Next to some other classes I have the simple class Data:
class Data{
public:
template <class T>
T dat();
int id;
union{
char c;
int i;
double d;
};
};
and the function dat:
template <class T>
T Data::dat(){
if(id == 1) return i;
if(id == 2) return d;
if(id == 3) return c;
}
As you can see, I want to check the id and return int, double or char.
Now I've tried to print the value in the main function like this:
Data test;
test.id=1;
test.i = 12;
cout<<test.dat();
But I always get this error message:
Error: Could not find a match for Data::dat<Data::T>() needed in main(int, char**).
Where is the problem??
Thank you
To put it precisely, you want the return type of the function to
depend on it's the id field in the object; in other words,
dynamically. Templates are resolved at compile time, so they
cannot help here. You'll have to return something like
boost::variant or boost::any, which supports such dynamic
typing.
Use this:
cout<<test.dat<int>();
dat() has no parameters involving T, so the compiler cannot deduce T from the call and it must be provided explicitly, e.g.:
cout << test.dat<int>();
Also, bear in mind you must implement dat() in the header file.
I don't know what to do. I always get an error by using a simple class and a simple template function. I read all the other solutions but they didn't helped me.
It seems to me that you want to create a discriminated union.
Your implementation won't work, because the return type of a template function is determined at compilation time (i.e. before you set a value in id and try to call the function.
Solution:
class Data
{
enum value_type {
int_val, char_val, double_val
} discriminator; // private (the user doesn't see this)
// this replaces your id
union{
char c;
int i;
double d;
} value;
public:
class wrong_type_error: public std::logic_error
{
public:
wrong_type_error(const std::string& msg): std::logic_error(msg) {}
};
explicit Data(const char c)
: discriminator(Data::char_value)
, value.c(c)
{
}
explicit Data(const int i)
: discriminator(Data::int_value)
, value.i(i)
{
}
explicit Data(const double d)
: discriminator(Data::double_value)
, value.d(d)
{
}
// don't put this here: int id;
// this part can be optimized to simpler (more idiomatic) code
template<typename T> T get() const; // undefined
template<> int get() const {
if(discriminator != Data::int_val)
throw wrong_type_error("Cannot return a int from Data instance");
return value.i;
}
template<> char get() const {
if(discriminator != Data::char_val)
throw wrong_type_error("Cannot return a char from Data instance");
return value.c;
}
template<> double get() const {
if(discriminator != Data::double_val)
throw wrong_type_error("Cannot return a double from Data instance");
return value.d;
}
};
Client code:
Data test(10.5);
cout<<test.get<double>();
All that said, you should consider using a boost::variant or boost::any instance, depending on your needs.
VS2012 says
"error C2783: 'T Data::dat(void)' : could not deduce template argument for 'T'"
You just need to tell the function dat what T is:
cout<<test.dat<int>();
The template type can be deduced if you pass a templated parameter, but it cannmot guess the return type.
Here's the deal. I've looked on this forum and I didn't find the information I'm searching for or I'm probably not able to repeat it for my problem. I have a class Table which is generic and I have a class named MyString.
template <typename typeGen, int DIM>
class Table {
public:
TableauGenerique() : index_(0) { //On initialise courant à 0
}
void add(typeGen type);
private:
typeGen tableGen_[DIM];
int index_;
};
My problem is with the add function.
I sometimes have to do this in the main.cpp: (which works well)
Table <float,6> tabFloat;
tabFloat.add(1.6564);
and at one point, I need to do this which doesn't work because I need to specialize the add function to create an object of MyString, to pass it the string and then store the object in the array (tableGen) :
TableauGenerique <MyString,4> tabString;
So I tried this (after the class), without success.
template <typename typeGen, int DIM>
void Table<typeGen,DIM>::add(typeGen type){ //Which is the generic one for float or ints
if(index_ < DIM) {
tableGen_[courant_] = type;
index_++;
}
}
template <class typeGen, int DIM>
void Table<typeGen,DIM>::add<string>(typeGen type) { //(line 75) Which is the specific or specialized function for myString
MyString str(type);
if(index_ < DIM) {
tableGen_[courant_] = str;
index_++;
}
}
So, How can I make this work because it doesn't compile at all, saying: line75 : error: expected initializer before '<' token and in the main it says not matching function to call Table::add(const char[6]),
I hope everything is clear enough. Let me know if somethings is unclear.
Thank you very much for your help !
template <class typeGen, int DIM>
void Table<typeGen,DIM>::add<string>(typeGen type)
You're trying to specialize add() when in fact it is not a function template to begin with. How do you expect it to work?
You probably meant: (specialization of the class)
template <int DIM>
void Table<string,DIM>::add(string type)
But then this is allowed only if you specialize the class itself. Without specializing the class, the above code would give compilation error!
EDIT:
You can read these online tutorials:
Introduction to C++ Templates
14.5 — Class template specialization
Template Specialization and Partial Template Specialization
Explicit specialization (C++ only)
If you can control the code of the MyString class, you can provide constructors that act as implicit conversions from float to MyString. An example:
#include <string>
#include <sstream>
#include <iostream>
class MyString {
public:
MyString(float number) {
std::stringstream buffer;
buffer << number;
value = buffer.str();
}
void print() {
std::cout << value << std::endl;
}
private:
std::string value;
};
template <class T>
class Foo {
public:
void DoStuff(T item) {
item.print();
}
};
int main() {
Foo<MyString> foo;
foo.DoStuff(1.342); // implicitly converts float to MyString
return 0;
}
This way, you do not need any specialization of the add method. However, implicit conversions are tricky, and you have be careful not to invoke them accidentally, and they may create ambiguities.
EDIT: Upon a second thought, my suggestion below is basically equivalent to
Table<MyString,4> tabString;
tabString.add(MyString("whatever"));
and therefore excessive and/or does not solve the problem. Feel free to ignore :)
I would extend the class Table with a generic method to add something from which you can construct an object of the desired type:
template <typename typeGen, int DIM>
class Table {
public:
Table() : index_(0) {}
void add(typeGen type);
// The additional method
template<typename T> void add(const T& src);
private:
typeGen tableGen_[DIM];
int index_;
};
template<typename typeGen, int DIM>
template<typename T>
void Table<typeGen,DIM>::add(const T& src) {
if(index_ < DIM) {
tableGen_[courant_] = typeGen(src);
index_++;
}
}
Note construction of a temporary typeGen object before the assignment.
Assuming that MyString object can be constructed from a string literal, i.e. from const char*, you can then use it as following:
Table<MyString,4> tabString;
tabString.add("whatever");
or if the above assumption is wrong, the following should probably work (because you constructed a MyString instance from a string instance):
tabString.add(string("whatever"));
I need to be able to pass a typename as a parameter:
int X = FileRead(file, 9, char);
The concept is for FileRead(std::fstream, int pos, ???) to read pos*sizeof(whatever the type is) to get the desired position. I tried templates:
template<typename T>
T FileRead(std::fstream file, int pos, T type)
{
T data;
file.read(reinterpret_cast<char*>(&data), sizeof(data));
return data;
}
but that required that I create a variable of the type to use every time I wanted to use FileRead, and I really don't feel like redesigning an entire program just because of one function, so is there anyway to use a typename as a parameter?
To use the name of a type as a parameter, use a template.
template<typename T>
T FileRead(std::fstream &file, int pos)
{
T data;
file.read(reinterpret_cast<char*>(&data), sizeof(T));
return data;
}
This assumes that the type is default constructible. If it is not, I guess you would have difficulty streaming it out of a file anyway.
Call it like this:
char value=FileRead<char>(file, pos);
If you do not want to have to specify the type in the call, you could modify your API:
template<typename T>
void FileRead(std::fstream &file, int pos, T &data)
{
file.read(reinterpret_cast<char*>(&data), sizeof(T));
}
Then call it like this - the type is inferred:
char value;
FileRead(file, pos, value);
Very simple:
template<typename T>
T FileRead(std::fstream file, int pos)
{
T data;
file.read(reinterpret_cast<char*>(&data), sizeof(data));
return data;
}
and call it via:
char x = FileRead<char>(file, pos);
I know this post is answered, but still, I had a problem with that and I found a simple way from this page answers. You can pass type name to any function like this:
template<typename T>
void function_name()
{
//you can access your type here with T
//you can create an object from T or anything you want
//for example :
T obj;
//or:
T obj=new T;
}
int main(){
function_name<YourTypeName>();
}
There is no such things as types once your program is compiled. This is the style of C++.