template class and using overloaded constructor with mixed parameters in c++ - c++

For my constructor and overloaded constructor definitions I have:
template <class T> Student<T>::Student(){}
template <class T> Student<T>::Student(string sName, int sAge) {
m_name = sName;
m_age = sAge;
}
I am getting confused on how to call a constructor with mixed parameters in the overloaded constructor.
My understanding is that if they were both ints I would do something like:
Student <int> newStudent;
newStudent(10, 15);

Student<int> is a type. Student<int> newStudent; creates a variable of that type, which means it is constructing that object. Since no arguments are included, the no-argument constructor is used.
newStudent(10, 15) is the attempting to call an ::operator()(int, int) member of that class, which may or may not be defined.
You probably want:
Student<int> newStudent("Mary", 15);
... to create a Student<int> type object in the variable newStudent.

Related

c++ Using a a template function with enum class and overloaded conversion operators

I was reading the sample code on another post Specializations only for C++ template function with enum non-type template parameter
and I'm trying to take it one step further, by using a overloaded conversion operator to use the object as if it was its enum member to call a template function.
//in my .h
enum class AllowedTypes { Cat, Dog };
class A {
AllowedTypes animal;
public:
//constructor
A(AllowedTypes t): animal(t) {};
explicit operator AllowedTypes*() const { return (AllowedTypes*) animal; }
operator AllowedTypes() const { return animal; }
template <AllowedTypes type>
void ability() const;
}
//second class
struct B{
//tempalte function
template <AllowedTypes type>
void ability() const;
}
//in my cpp
template<>
void B::ability<AllowedTypes::Dog>() const
{
std::cout << "Dog ability." << std::endl;
}
template<>
void B::ability<AllowedTypes::Cat>() const
{
std::cout << "Cat ability." << std::endl;
}
//in my main
Class* a = new A(AllowedType(1))
Class* b = new B();
//this calls work!
b->ability<AllowedTypes::Cat>();
//trying to get the type and calling ability via conversion doesn't
AllowedTypes type = (AllowedTypes)*a; // this converts correctly!
b->ability<type>(); //does not call correctly
this last line doesn't work, I'm trying to put my converted object in the template and call the ability specific to the type that A has. I've tried a few different things but can't seem to find what I'm looking for, is there a proper way to do this?
The problem in your code is that you are trying to set a template type parameter using a runtime value rather than compile time value.
Class* a = new A(AllowedType(1)) // The call to new here makes 'type' below a runtime value
b->ability<AllowedTypes::Cat>(); // AllowedTypes::Cat can be supplied at compile time
AllowedTypes type = (AllowedTypes)*a; // this converts correctly!
b->ability<type>(); //does not call correctly
Here is your code running online which points to the exact problem. Next time your confused about why your template type isnt getting deduced correctly/throwing an error use constexpr to figure out why.
And here is an answer explaining why new results in an ill-formed constexpr: C++14: can you call new in a constexpr?

Calling a constructor inside a constructor of a templated class

This code has a templated class. The default constructor appears to call itself recursively. How can it do that? I don't understand this code. Maybe if I would be given an example without templates, just POD types, things would be clearer. I haven't encountered this construct before in C++ programming. I think that I don't understand both the constructor and the templates.
template <typename T>
class Simple {
public:
Simple(T value = T()); // What's this?
T value();
void set_value(T value);
private:
T value_;
};
template<typename T>
Simple<T>::Simple(T value) {
value_ = value;
}
template<typename T>
T Simple<T>::value() {
return value_;
}
template<typename T>
void Simple<T>::set_value(T value) {
value_ = value;
}
My question is:
What does T value = T() do?
Class Simple has a variable value of type T (Templated).
The constructor which you are pointing is a default constructor. When no parameter is supplied while creating Simple object. Then default constructor will instantiate the value object to the default constructor of T.
Either , Simple(T value = T()) is a default constructor which is instantiating value to default constructor of typed element.
Example :-
if T is String.
Simple (String value = String())
so value is now initialized to default of String().
It is just a default value as void foo(int i = 42);, there are no recursion.
foo(); is equivalent to foo(42);.
In the same way, with Simple(T value = T());
Simple<int> s{}; would be equivalent to Simple<int> s{0}; and
Simple<std::string> s{}; would be equivalent to Simple<std::string> s{std::string{}}; (empty string).
T() would call the default constructor of given T (int and std::string in my examples).

Template and using (#define) in class constructor

I've implemented stack process.this program is supposed to work exactly the same as a real stack memory.moreover i'm trying to use Template and make the the program more generic. I've got a problem in using #define DEFAULT_SIZE 10 as the argument of class constructor.
First of all when i put DEFAULT_SIZE in the prototype of the constructor it goes smoothly:
#define DEFAULT_SIZE 10
template<typename T>
class stack {
public:
stack(int size=DEFAULT_SIZE);
private:
T *elements;
int size;
int count;
};
template<typename T>
stack<T>::stack(int s) {
cout << "--constructor called\n";
size = s;
elements = new T[size];
count = 0;
}
But when I just put DEFAULT_SIZE in outline definition of the class constructor i get this error: no appropriate default constructor available
#define DEFAULT_SIZE 10
template<typename T>
class stack {
public:
stack(int size);
private:
T *elements;
int size;
int count;
};
template<typename T>
stack<T>::stack(int s=DEFAULT_SIZE) {
cout << "--constructor called\n";
size = s;
elements = new T[size];
count = 0;
}
Finally the main of the program:
int main() {
stack<int> u;
u.push(4);
}
My question is not about "Why can templates only be implemented in the header file?" My problem is the place where I use DEFAULT_SIZE.
I suppose, the problem is just in difference of template declaration:
stack(int size);
and template definition:
stack<T>::stack(int s=DEFAULT_SIZE) {
...
}
Default values must be in declaration part, and if method signature in definition is different from declaration (you add DEFAULT_SIZE in definition) compiler is not sure you write the same constructor. Note, DEFAULT_SIZE is applied when s value not given to constructor, so you definition will work as default constructor, but declaration is constructor with one parameter.
It is mentioned in C++ specs(ยง8.3.6 pt.4) that
For non-template functions, default arguments can be added in later declarations of a function in the same scope.
So you can't assign the default value in the definition. That is the reason for not working of second approach.
While first approach will work as it is a desired behavior that you can omit the default values in the definition.
If you compile your second code snippet with Ideone for example it gives you "redeclaration of 'stack::stack(int)' may not have default arguments" (see http://ideone.com/UKIx2r).
prog.cpp:16:35: error: redeclaration of 'stack<T>::stack(int)' may not have default arguments [-fpermissive]
stack<T>::stack(int s=DEFAULT_SIZE) {
Default parameters have to be specified in the first declaration
If you declare your own constructors the default constructor will be deleted. However, your constructor will act as a default constructor as long as all parameters have default values.
Your first part declares a correct default value for the constructors parameter. Your second part does not and your compiler has no chance to use the constructor as a default constructor.

c++ custom container pass {} list

I am basically remaking the set container and I am wondering how I pass a brace-enclosed initializer list to the container.
mySet<int> myset = {"test", "test 2"};
I tried to overload the operator= to take a list as a parameter.
Despite the presence of the = here, this is constructing a set, so what you need is a constructor (that takes an std::initializer_list as its parameter).
template<class T>
class myset {
public:
// ...
mySet(std::initializer_list<T> init) {
for (T const &t : init)
insert(t);
}
};
You need to implement a constructor which take a std::initializer_list as its parameter, such as:
template <class T>
class mySet {
public:
mySet(std::initializer_list<T> l) {
// ...
}
};
Define a constructor that takes a std::initializer_list as a parameter, like
mySet(std::initializer_list<T> args){/*...*/}
operator= is invoked only on assignments, not on copy initialization (your case). In this latter case the constructor is invoked on the rhs, followed by a copy (or move), which is usually elided, but nevertheless the copy or move ctors must be accessible.

Finding typeid of a template parameter

The print statement in the constructor's definition doesn't get printed, isn't the constructor calling correct in main? I know I am missing some point here, please point out.
#include <iostream>
#include <typeinfo>
template <typename T> class List
{
public:
template <typename T2> List (List<T2> const&);
};
template <typename T> template <typename T2> List <T> :: List (List <T2> const&)
{
std :: cout << "\nType name:" << typeid (T2).name();
}
int main ()
{
List <int> kk (List <int>);
return 0;
}
There are a couple of things wrong in your code that you might not be aware of.
List<int> kk( List<int> );
That line is not a variable definition, but rather the declaration of a function that takes a List<int> as argument and returns a List<int>, so that effectively will not call any constructor. That is know as the most-vexing-parse (you can look at different versions of it by searching in SO, or in the C++ FAQ lite)
The second issue is that you cannot possibly create any instance of the an instantiated type of List, the reason being is that the only constructor that you are providing is a templated constructor that takes a second List<U> as argument. That effectively disables the default constructor, so the only way of creating a List<T> is by already having a List<U>, and that is not possible. You can add the default constructor back:
template <typename T>
class List {
public:
List() {}
template <typename U>
List( List<U> const & ) {} // prefer const& as that will avoid unnecessary copying
};
And now you can write:
List<int> l = List<int>(); // this will call List<int>::List( List<int> const & )
And yet, that will still not call the constructor you want. The reason is a little obscure, but when copy constructing an element of a template, the compiler will not use a templated constructor. In the code above, it will implicitly define a copy constructor by doing member-wise copy constructor of the methods and call that generated constructor. That means that in most occasions where you want to provide a templated constructor you want to also provide a non-templated copy constructor.
To actually call that constructor you would have to provide a different type:
List<int> l = List<double>();
Since the types actually differ, the compiler cannot copy construct, will find that the provided templated constructor is the best overload candidate and call it.
As well as the "most vexing parse" identified by David:
you need to have at least one more constructor to create the original List object to be passed to the copy constructor,
you need to vary the parameter type in order to have the templated copy constructor invoked: as is you'll match the implicitly declared List(const List&) copy constructor instead.
So:
#include <iostream>
template <typename T>
struct X
{
X() { std::cout << "X()\n"; }
// implicitly like this anyway...
// X(const X& rhs) { std::cout << "X(X&)\n"; }
template <typename U>
X(const U& u) { std::cout << "U\n"; }
};
int main()
{
X<int> x;
X<int> y(x);
}
What are you trying to do with this statement:
List <int> kk (List <int>);
(It actually declares a function, and can't be anything but
a function declaration.)
In order to see output from the copy constructor, you've got to
invoke the copy constructor somehow. Which means having an
object to copy. Which isn't possible with the code you've
given: since you've explicitly declared a constructor, the
compiler will not provide a default constructor, and you have no
other constructor with which to create an object. So you have
no way of creating anything to copy. If you add a
List() {}
to the class, and write:
List<int> kk((List<int>());
, you might get something, but the compiler is allowed to elide
the copy here, so more likely there will be no output. Try:
List<int> a;
List<int> b(a);
Or just put your output in the default constructor.