C++ Templated class function that can detect std::vector - c++17

If I have a templated class, I can do the following to detect if a vector was passed:
template<typename T> struct is_vector { static const bool value=false; };
template<typename T> struct is_vector<std::vector<T>> { static const bool value=true; };
template<class T>
class Parser {
public:
Parser() {}
void parse(T obj) {
if (is_vector<T>::value) {
std::cout << "vector\n";
//obj.push_back(T {});
}
else {
std::cout << "not vector\n";
}
}
};
int main() {
Parser<int> p1;
p1.parse(123);
Parser<std::vector<int>> p2;
p2.parse({ 1, 2, 3});
return 0;
}
Output:
not vector
vector
I can detect a vector, yet the compiler complains when I uncomment the push_back call:
main.cpp: In instantiation of ‘void Parser<T>::parse(T) [with T = int]’:
main.cpp:26:14: required from here
main.cpp:15:17: error: request for member ‘push_back’ in ‘obj’, which is of non-class type ‘int’
obj.push_back(T {});
~~~~^~~~~~~~~
Obviously, an int does not have a push_back function, but the vector does. The is_vector call is evaluated at runtime, but the push_back is caught at compile time.
With partial template specialization, I can do what I want:
template<typename T>
void parse(T obj) {
std::cout << "not vector: " << obj << "\n";
}
template<typename T>
void parse(std::vector<T> obj) {
std::cout << "is vector\n";
for (auto i : obj) std::cout << i << " ";
obj.push_back(T {});
std::cout << "\n";
for (auto i : obj) std::cout << i << " ";
std::cout << "\n";
}
int main() {
parse(1);
parse('a');
parse(std::vector<int> { 1, 2, 3 });
return 0;
}
Output:
not vector: 1
not vector: a
is vector
1 2 3
1 2 3 0
So, how can I combine these 2 ideas, either at compile-time or at runtime? That is, have a templated class with a function that can handle vectors and non-vectors?

What you're looking for is a new feature in C++17, if constexpr. It's the same as a regular if, except that the condition is evaluated at compile time, and when instantiating the branch(es) will discard the non-taken branch at compile time. The discarded branch does not need to well-formed. So, for your example:
template<class T>
class Parser {
public:
Parser() {}
void parse(T obj) {
if constexpr (is_vector<T>::value) {
std::cout << "vector\n";
obj.push_back(T {});
}
else {
std::cout << "not vector\n";
}
}
};
See Difference between if constexpr vs if for some more talk on the differences. You can also read the cppreference page on if statements to get a detailed overview of some of the nitty-gritty details.

Related

why can't I pass an l-value to a template class constructor that uses universal references?

I have a templated class MyClass<T> that takes some iterable containing ints (e.g. T = std::vector<int>) in its constructor and does something with it.
I would like to be able to pass the iterable as either a temporary object (e.g. MyClass(std::vector<int>{3,6,9}) or similar r-value argument) or from a named variable (resulting in an l-value as the constructor argument).
I would like to use C++17 template class inference (i.e. write MyClass(...), not MyClass<std::vector<int>>(...)).
I thought that I could declare the constructor parameter as MyClass(T && vec) (a "universal reference") to take either an l-value or an r-value (just like I can with functions), but it gives an error. It seems like T is always inferred as std::vector<int> and never std::vector<int>& with classes, whereas functions infer std::vector<int>& when the argument is an l-value.
How exactly are the rules for template constructor inference and template function inference different? Can I avoid having to use a wrapper function (e.g. myFunction(T&&vec) { return MyClass<T>(std::forward<T>(vec)); }) just for the sake of template inference?
Run the code below on Godbolt:
#include <iostream>
#include <utility>
#include <vector>
template <typename T>
using BeginType = decltype(std::declval<T>().begin());
template <typename T>
struct MyClass {
BeginType<T> begin;
BeginType<T> end;
MyClass(T && vec) {
begin = std::forward<T>(vec).begin();
end = std::forward<T>(vec).end();
}
int sum() {
int sum = 0;
for (auto it = begin; it != end; ++it) sum += *it;
return sum;
}
};
template <typename T>
MyClass<T> myFunction(T && vec) {
return MyClass<T>(std::forward<T>(vec));
}
int main() {
std::vector<int> x{1, 2, 3};
std::vector<int> y{2, 4, 6};
// Warmup: Passing r-values works fine
std::cout << MyClass(std::vector<int>{3, 6, 9}).sum() << std::endl; // works fine: T is std::vector<int>
std::cout << MyClass(std::move(y)).sum() << std::endl; // works fine: T is std::vector<int>
// Unexpected: Passing l-values doesn't work
// std::cout << MyClass(x).sum() << std::endl; // error: cannot bind rvalue reference of type 'std::vector<int>&&' to lvalue of type 'std::vector<int>'
// Compare: Passing l-values to function works fine
std::cout << myFunction(x).sum() << std::endl; // works fine: T is std::vector<int>&
}
Add a user-defined deduction guide after the class definition:
template <typename T>
struct MyClass {
// same as in question
};
template <typename TT> MyClass(TT && vec) -> MyClass<TT>;
See also How to write a constructor for a template class using universal reference arguments in C++

Getting inheritance issues when trying to compile

I have a class called stackTester that is trying to inherit from another class stackofChars. The methods defined in stackofChars that I am trying to use in stackTester are all virtual, but when I try to use them in stackTester, I get an error
request for member which is of non-class type
Here is my stackofChars.h file:
#define STACK_OF_CHARS_H
#include "node.h"
class stackofChars
{
private:
node* m_top;
public:
//constructor for the stack, takes in no paramaters
stackofChars();
//copy constructor, takes in a referance to the original stack
stackofChars(const stackofChars& orig);
//destructor for the stack, no parameters
~stackofChars();
//destructor for the copy, takes in a referance to the copy
void operator=(const stackofChars& rhs);
//pushes the stack back and creates a new node at the stop, takes in an entry, returns nothing
virtual void push(char entry);
//deletes the top entry and pushes the stack up, takes in nothing, returns nothing
virtual void pop();
//peeks at the top entry, takes in nothing, returns a char, const because nothing is changed
virtual char peek() const;
//checks if the stack is empty, takes in no parameters, returns nothing, const because nothing is changed
virtual bool isEmpty() const;
};
#endif
Here is my stackTester.h file:
#ifndef STACK_TESTER_H
#define STACK_TESTER_H
#include "stackofChars.h"
class stackTester : public stackofChars
{
public:
stackTester();
//This will call all your test methods
void runTests();
private:
//Creates an empty stack and verifies isEmpty() returns true
void test1();
//Creates an empty stack pushes 1 value, verifies isEmpty() returns false
void test2();
//Creates an empty stack, then pushes once, pops once, and verifies isEmpty returns true
void test3();
//more test methods as needed
};
#endif
If needed, here is my stackTester.cpp file:
#include "stackTester.h"
#include "stackofChars.h"
#include <iostream>
void stackTester::test1()
{
stackofChars test();
std::cout << "Test#1: Newly created stack is empty: ";
if(test.isEmpty() == true)
{
std::cout << "Pass\n";
}
else
{
std::cout << "Fail\n";
}
}
void stackTester::test2()
{
stackofChars test();
test.push(???);
std::cout << "Test#2: Push on empty stack makes it non-empty: ";
if(test.isEmpty() == true)
{
std::cout << "Pass\n";
}
else
{
std::cout << "Fail\n";
}
}
void stackTester::test3()
{
stackofChars test();
test.push(???);
test.pop();
std::cout << "Test#3: Popping all elements makes stack empty: ";
if(test.isEmpty() == true)
{
std::cout << "Pass\n";
}
else
{
std::cout << "Fail\n";
}
}
Can someone tell me why I am getting this error?
stackofChars test(); is wrong.The right way to declare a class object should be: stackofChars test; or stackofChars test{};
There is an explanation here enter link description here

Check if T has operator<< [duplicate]

This question already has answers here:
How to check whether operator== exists?
(14 answers)
Closed 3 years ago.
I am writing code to compare to instances of various types. The final comparison function is quite simple - with signature:
template <typename T>
int not_equal(const T& arg1, const T& arg2) {
if (arg1 == arg2)
return 0;
std::cerr << "Error when comparing" << std::endl;
return 1;
}
Now - I would like to add the actual values being compared in the std::cerr message as:
std::cerr << "Error when comparing " << arg1 << " != " << arg2 << std::endl;
however - many of the classes do not have operator<< - and that is OK. For the classes which do not support operator<< I just want the classname - i.e. the pseudo code should be something like:
if (supports_operator<<<T>)
std::cerr << "Error when comparing " << arg1 << " != " << arg2 << std::endl;
else
std::cerr << "Error when comparing instances of type: " << typeid(arg1).name() << std::endl;
Can I have my fictitious supports_operator<<<T>()functionality?
Edit: I am limited to C++17
If you are able to use C++20 and concepts, then you can do something like this:
#include <iostream>
#include <concepts>
template <typename T>
concept Streamable = requires (T x) { std::cout << x; };
struct Foo {};
struct Bar {};
std::ostream& operator<<(std::ostream& os, Foo const& obj) {
// write obj to stream
return os;
}
template <Streamable T>
void foo(T const& t) {
std::cout << t << std::endl;
}
int main() {
Foo f;
Bar b;
foo(f);
foo(b); // error
return 0;
}
Demo

User Input in C++ like in Python

#Python code
user = input("Please enter your name \n")
print ("Your name is,", user)
How can I make this in C++?
I don't exactly know what you want to achieve, but I think this is what you're looking for.
#include<iostream>
#include<string>
using namespace std;
int main()
{
string user;
/* ---- This part is in place of your python code --- */
cout << "Please Enter your name"; cin >> user;
cout << "Your name is" << user;
/* --------------------- */
return 0;
}
Unfortunately, the accepted answer does not match the legitimate question, how to realize the input.
Consider this solution:
#include <iostream>
#include <string>
template<typename T>
T input(std::string message = "")
{
if (!empty(message)) std::cout << message << " : ";
T value;
std::cin >> value;
return value;
}
int main()
{
auto i = input<int>("integer, followed by decimal point value");
auto d = input<double>();
if (std::cin) std::cout << "Gelesen: " << i << ' ' << d << '\n';
else std::cout << "error reading input";
}
The input() function does not return a string like in Python, but a value of the type indicated in angle brackets.

Templated Stack Linked List

I have written a templates stack linked list for an assignment I have to complete. When I run it, it prints out the first element, but then crashes. Any ideas on what could be going wrong? I have a feeling it might be the pop function, but its so basic, I'm not sure what is even wrong.
template<typename T>
struct StackNode
{
T data;
StackNode* next;
StackNode(T t, StackNode* ptr);
~StackNode();
};
template <typename T>
StackNode<T>::StackNode(T t, StackNode* ptr = nullptr)
:data(t), next(ptr)
{
}
template <typename T>
StackNode<T>::~StackNode()
{
delete next;
}
template<typename T>
struct LinkedStack
{
LinkedStack();
LinkedStack(const StackNode<T> &s);
~LinkedStack();
bool isEmpty();
void push(const T& t);
void pop();
T top();
StackNode<T>* head;
int numElements;
};
template <typename T>
LinkedStack<T>::LinkedStack()
: head(nullptr), numElements(0)
{
}
template<typename T>
LinkedStack<T>::LinkedStack(const StackNode<T> &s)
: head(nullptr), numElements(0)
{
for (auto t = s.head; t; t = t->next)
push(t->item);
}
template<class T>
LinkedStack<T>::~LinkedStack()
{
while (!isEmpty())
{
pop();
}
}
template<typename T>
bool LinkedStack<T>::isEmpty()
{
if (numElements > 0)
{
return false;
}
else
{
return true;
}
}
template<typename T>
void LinkedStack<T>::push(const T& t)
{
head = new StackNode<T>(t, head);
numElements++;
}
template<typename T>
void LinkedStack<T>::pop()
{
if (isEmpty())
{
cout << "Stack is empty." << endl;
}
else
{
StackNode<T>* oldnode = head;
head = head->next;
numElements--;
delete oldnode;
}
}
template<typename T>
T LinkedStack<T>::top()
{
if (isEmpty())
{
cout << "Stack is empty..." << endl;
}
else
{
return head->data;
}
}
int main()
{
LinkedStack<string> x;
x.push("Test");
x.push("One");
x.push("Two");
x.push("Three");
cout << "Now popping all elements of the stack:" << endl;
while (x.isEmpty() == false)
{
cout << x.top() << endl;
x.pop();
}
}
When you delete a node, you also delete the node it points to :
template <typename T>
StackNode<T>::~StackNode()
{
delete next;
}
When you pop an item, you delete the whole linked list as the deletion propagate from a node to another. The segfault is raised after deleting the last node, your programs try to delete nullptr.
The delete statement in the pop function is enough. No need to delete Stacknode.next as you do not assign it with the new keyword
I've successfully runned your code after removing the problematic delete.

Resources