C++ How to write a friend function binary operator which lives in a namespace in a separate compilation unit - c++17

I can't seem to figure out how to get the following to compile.
I am trying to write a binary operator which:
Is defined in a separate compilation unit (file)
Lives in a nested namespace
Here's some code:
// header.h
namespace ns1
{
namespace ns2
{
class myClass
{
friend bool operator==(const myClass& l, const myClass& r);
protected:
int a;
};
}
}
// header.cpp
#include "header.h"
using namespace ns1;
using namespace ns1::ns2;
bool operator==(const myClass& l, const myClass& r)
{
if(l.a != r.a) return false;
return true;
}
// main.cpp
#include "header.h"
using namespace ns1::ns2;
using namespace std;
int main()
{
myClass class1;
myClass class2;
if(class1 == class2)
{
cout << "hello world" << endl;
}
return 0;
}
This is the output from the compiler:
In function ‘bool operator==(const ns1::ns2::myClass&, const ns1::ns2::myClass&)’:
error: ‘int ns1::ns2::myClass::a’ is protected within this context
I have a suspicion that this is related to the compiler not understanding which namespace operator== should be in. I have tried explicitly declaring this, but that didn't help either.
The question is what is going on here? What is the compiler thinking?
Edit
Note: I posted this edit in response to an answer which was then deleted. The suggestion was to put the operator inside ns1::ns2, however this did not work. See the below output.
New compiler output:
error: ‘bool ns1::ns2::operator==(const ns1::ns2::myClass&, const ns1::ns2::myClass&)’ has not been declared within ‘ns1::ns2’ [-Werror]
bool ns1::ns2::operator==(const myClass& l, const myClass& r)
note: only here as a ‘friend’
friend bool operator==(const myClass& l, const myClass& r);

The problem here is when you declare a friend function inside your class, this function belongs to the innermost enclosing namespace, you have to define
bool ns1::ns2::operator==(const myClass& l, const myClass& r)
It should be defined inside namespace ns1::ns2 but not just introduced it with using directives,
// header.cpp
#include "header.h"
namespace ns1 {
namespace ns2 {
bool operator==(const myClass& l, const myClass& r)
{
if(l.a != r.a) return false;
return true;
}
}
}
Demo
or
// header.h
namespace ns1
{
namespace ns2
{
class myClass
{
...
};
bool operator==(const myClass& l, const myClass& r);
}
}
// header.cpp
bool ns1::ns2::operator==(const myClass& l, const myClass& r)
Demo
Another way is to declare your friend function as a global one,
// header.h
#pragma once
namespace ns1
{
namespace ns2
{
class myClass;
}
}
bool operator==(const ns1::ns2::myClass& l, const ns1::ns2::myClass& r);
namespace ns1
{
namespace ns2
{
class myClass
{
friend bool ::operator==(const myClass& l, const myClass& r);
protected:
int a;
};
}
}
// header.cpp
#include "header.h"
using namespace ns1::ns2;
bool operator==(const myClass& l, const myClass& r)
{
if(l.a != r.a) return false;
return true;
}
Demo

Related

How to match a struct member access using clang AST matcher?

I am trying to write a clang-tidy check to rename struct members.
For this, I need to match MemberExpr nodes that access a certain member, from certain structs.
In the following code, it should only match all uses of member on types S1 and S2 (8 matches in total).
typedef struct S1 { int member; int v; } S1; typedef struct MS1 {S1 s1; } MS1;
typedef struct S2 { int member; int v; } S2; typedef struct MS2 {S2 s2; } MS2;
typedef struct S3 { int member; int v; } S3; typedef struct MS3 {S2 s3; } MS3;
void f() {
S1 *s1a, s1b; MS1 *ms1a, ms1b;
S2 *s2a, s2b; MS2 *ms2a, ms2b;
S3 *s3a, s3b; MS3 *ms3a, ms3b;
(void)s1a->member; (void)s1b.member; (void)ms1a->s1.member; (void)ms1b.s1.member;
(void)s2a->member; (void)s2b.member; (void)ms2a->s2.member; (void)ms2b.s2.member;
(void)s3a->member; (void)s3b.member; (void)ms3a->s3.member; (void)ms3b.s3.member;
(void)s1a->v; (void)s1b.v; (void)ms1a->s1.v; (void)ms1b.s1.v;
(void)s2a->v; (void)s2b.v; (void)ms2a->s2.v; (void)ms2b.s2.v;
(void)s3a->v; (void)s3b.v; (void)ms3a->s3.v; (void)ms3b.s3.v;
}
The matcher memberExpr(member(hasName("member"))) is too broad and also includes type S3.
How can I limit the matcher to only return those member accesses of S1 and S2?
Thanks.

C++17 alternative to C++20 "requires" keyword

C++20 introduced many improvements like requires, concepts, constraints, modules and much more - functionality you really miss in C++17.
How can a scenario having conditional constructors be implemented in C++17, that could look like the following C++20 example (using requires)?
template <typename T> concept has_type = requires { typename T::type; };
template <typename T>
class someClass {
public:
using data_t = typename std::conditional_t<has_type<T>, T, std::type_identity<T> >::type;
constexpr someClass(T const& _a, T const& _b) requires std::is_arithmetic_v<T> : a{_a}, b{_b} {}
constexpr someClass(data_t const& _a, data_t const& _b,) requires has_type<T> : a{_a}, b{_b} {}
private:
const data_t a, b;
};
One constructor has to be used in case of T is an arithmetic type (int, float, double, ...).
Another constructor needs to catch the case of T being a class/struct having a nested type alias (e.g. struct x { using type=float; };).
Using SFINAE
template <typename, typename = std::void_t<>>
struct HasTypeT : std::false_type {};
template <typename T>
struct HasTypeT<T, std::void_t<typename T::type>> : std::true_type {};
template <typename T>
struct type_identity {
using type = T;
};
template <typename T>
class someClass {
public:
using data_t = typename std::conditional_t<HasTypeT<T>::value, T, type_identity<T> >::type;
template <typename U = T, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr someClass(T const& _a, T const& _b) : a{_a}, b{_b} {}
template <typename U = T, typename = std::enable_if_t<HasTypeT<U>::value>>
constexpr someClass(typename U::type const& _a, typename U::type const& _b) : a{_a}, b{_b} {}
private:
const data_t a, b;
};
Demo

C++ Templated class function that can detect std::vector

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.

Virtual function overloading and signature

I thought that since f's argument is float - the float version of f will be called, but that's not the case. Why is it?
Thank you!
class A
{
public: virtual void f(int n)
{
cout<<"A"<<endl;
}
};
class B: public A
{
public: virtual void f(float f)
{
cout<<"B"<<endl;
}
};
int main()
{
A* ptr = new B;
ptr->f(6.66);
delete ptr;
}

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