C++ class (with set) storing a generic template class...compilation problems - c++

So I'm still some what new to C++ programming and very new at templates. I am trying to make a basic template class (a node if you will) that holds some generic data and a double. I then want to make another class contain a set of the previously mentioned template class.
Im having trouble with the less-than operator as its going to server as my comparator.
Node&Tree.h
#ifndef _POINTNODE_H_
#define _POINTNODE_
#include <set>
template<typename T>
class PointNode {
public:
PointNode(double p){ m_point = p;}
~PointNode();
bool operator < (const &PointNode<T> p1) const;
private:
const double m_point;
T *m_data;
};
template <typename T>
class PointTree {
public:
PointTree();
~PointTree();
private:
std::set<PointNode<T> > tree;
};
#endif
Node&Tree.cpp
#inlcude "Node&Tree.h"
#include <set>
template<typename T>
bool PointNode<T>:: operator < (const &PointNode<T> p1) const{
return m_point < p1.m_point;
}
Im getting the folowing errors
Node&Tree.cpp:5:39: error: ISO C++ forbids declaration of ‘parameter’ with no type [- fpermissive]
Node&Tree.cpp:5:39: error: expected ‘,’ or ‘...’
Node&Tree.cpp:5:6: error: prototype for ‘bool PointNode<T>::operator<(const int&) const’ does not match any in class ‘PointNode<T>’
Node&Tree.h:15:8: error: candidate is: bool PointNode<T>::operator<(const int&)"
This is largely unimplemented but I just wanted to get the basics to compile at least... And any pointers on the code or if you think I'm going about this all wrong please tell me!
Any help would be amazing!

bool PointNode<T>:: operator < (const &PointNode<T> p1) const
should be:
bool PointNode<T>:: operator < (const PointNode<T>& p1) const
You put the reference & in the wrong position, so you have that forbids declaration of parameter error. Another place has the same error.
bool operator < (const &PointNode<T> p1) const;
should be
bool operator < (const PointNode<T>& p1) const;

Make PointNode object as reference
bool operator < (const PointNode<T>& p1) const;
And its defination
template<typename T>
bool PointNode<T>:: operator < (const PointNode<T>& p1) const{
return m_point < p1.m_point;
}
this will fix the problem.

Related

How to create a common range?

Why doesn't std::ranges::common_view compile in the code below?
#include <ranges>
#include <vector>
#include <algorithm>
template <class T>
struct IteratorSentinel {};
template <class T>
class Iterator
{
public:
using iterator_category = std::input_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
Iterator() = default;
Iterator(const Iterator&) = delete;
Iterator& operator = (const Iterator&) = delete;
Iterator(Iterator&& other) = default;
Iterator& operator = (Iterator&& other) = default;
T* operator-> () { return cur(); }
T& operator* () { return *cur(); }
T& operator* () const { return *cur(); };
bool operator== (const IteratorSentinel<T>&) const noexcept;
Iterator& operator++ ();
void operator++ (int);
private:
T* cur() const
{
return pCur;
}
T* pCur = nullptr;
};
static_assert(std::input_iterator<Iterator<int>>);
template <class T>
auto make_range()
{
return std::ranges::subrange(Iterator<T>(), IteratorSentinel<T>{});
}
int main()
{
auto r = make_range<int>();
auto cr = std::ranges::common_view{ r };
std::vector<int> v;
std::copy(cr.begin(), cr.end(), std::back_inserter(v));
return 0;
}
Can't figure out what template parameter does it require.
MSVC2022 error (/std:c++latest):
error C2641: cannot deduce template arguments for 'std::ranges::common_view'
error C2893: Failed to specialize function template 'std::ranges::common_view<_Vw> std::ranges::common_view(_Vw) noexcept(<expr>)'
GCC12 errors:
prog.cc: In function 'int main()':
prog.cc:67:43: error: class template argument deduction failed:
67 | auto cr = std::ranges::common_view{ r };
| ^
prog.cc:67:43: error: no matching function for call to 'common_view(std::ranges::subrange<Iterator<int>, IteratorSentinel<int>, std::ranges::subrange_kind::unsized>&)'
In file included from prog.cc:1:
/opt/wandbox/gcc-12.1.0/include/c++/12.1.0/ranges:3724:7: note: candidate: 'template<class _Vp> common_view(_Vp)-> std::ranges::common_view<_Vp>'
3724 | common_view(_Vp __r)
| ^~~~~~~~~~~
Your range is built out of an iterator/sentinel pair. The definition of a common range is a range where the sentinel type is an iterator. So the range itself is not a common range.
common_view can generate a common range from a non-common range. Which means that it will have to create two iterators. And since it starts the process with only one iterator, that means that, at some point, it must copy that iterator (thus creating two usable iterators).
Which it can't do because your iterator is non-copyable. Which is why common_view has an explicit requirement that the iterator is copyable.

deleted friend declaration declares a non-template function

I want to delete a specific overloaded friend function in a class.
The below code compiles, and works in the way intended.
However, I get the following warning (g++, c++11,14,17):
edit: Warning is present using gcc9.3 and older, but not for gcc10
warning: friend declaration 'bool operator==(const MyType<BaseT>&, const BaseT&)' declares a non-template function [-Wnon-template-friend]
6 | friend bool operator==(const MyType<BaseT> &lhs, const BaseT &rhs) = delete;
| ^~~~~~
new.cpp:6:72: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
Can someone shed light on the warning? Why does it apply for the deleted function, but not the implemented one?
template <typename BaseT> struct MyType {
BaseT v;
explicit MyType(BaseT tv) : v(tv) {}
explicit operator BaseT() const { return v; }
friend bool operator==(const MyType<BaseT> &lhs, const BaseT &rhs) = delete;
friend bool operator==(const MyType<BaseT> &lhs, const BaseT &&rhs) {
return lhs.v == rhs;
}
};
int main(){
MyType<int> a{3};
int b{3};
// a==b; //Fails to compile: good. Do not allow comparisons between different types
a==3; //Compiles fine: good. Allow literal comparison, without implicit constructor
}

operator== does not compile if I include <iostream>

The following code compiles perfectly if:
I don't include <iostream> or
I name operator== as alp::operator==.
I suppose there is a problem with <iostream> and operator==, but I don't know what.
I compile the code with gcc 7.3.0, clang++-6.0 and goldbolt. Always the same error.
The problem is that the compiler is trying to cast the parameters of operator== to const_iterator, but why? (I suppose the compiler doesn't see my version of operator==, and looks for other versions).
#include <vector>
#include <iostream> // comment and compile
namespace alp{
template <typename It_base>
struct Iterator {
using const_iterator = Iterator<typename It_base::const_iterator>;
operator const_iterator() { return const_iterator{}; }
};
template <typename It_base>
bool operator==(const Iterator<It_base>& x, const Iterator<It_base>& y)
{ return true;}
}// namespace
struct Func{
int& operator()(int& p) const {return p;}
};
template <typename It, typename View>
struct View_iterator_base{
using return_type = decltype(View{}(*It{}));
using const_iterator =
View_iterator_base<std::vector<int>::const_iterator, Func>;
};
using view_it =
alp::Iterator<View_iterator_base<std::vector<int>::iterator, Func>>;
int main()
{
view_it p{};
view_it z{};
bool x = operator==(z, p); // only compiles if you remove <iostream>
bool y = alp::operator==(z,p); // always compile
}
Error message:
yy.cpp: In instantiation of ‘struct View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>’:
yy.cpp:9:73: required from ‘struct alp::Iterator<View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func> >’
yy.cpp:44:29: required from here
yy.cpp:28:42: error: no match for call to ‘(Func) (const int&)’
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
yy.cpp:22:10: note: candidate: int& Func::operator()(int&) const <near match>
int& operator()(int& p) const {return p;}
^~~~~~~~
yy.cpp:22:10: note: conversion of argument 1 would be ill-formed:
yy.cpp:28:42: error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
I've made a more minimal test case here: https://godbolt.org/z/QQonMG .
The relevant details are:
A using type alias does not instantiate a template. So for example:
template<bool b>
struct fail_if_true {
static_assert(!b, "template parameter must be false");
};
using fail_if_used = fail_if_true<true>;
will not cause a compile time error (if fail_if_used isn't used)
ADL also inspects template parameter classes. In this case, std::vector<int>::iterator is __gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>, which has a std::vector<int> in it's template. So, operator== will check in the global namespace (always), alp (As alp::Iterator is in alp), __gnu_cxx and std.
Your View_iterator_base::const_iterator is invalid. View_iterator_base::const_interator::result_type is defined as decltype(Func{}(*std::vector<int>::const_iterator{})). std::vector<int>::const_iterator{} will be a vectors const iterator, so *std::vector<int>::const_iterator{} is a const int&. Func::operator() takes an int&, so this means that the expression is invalid. But it won't cause a compile time error if not used, for the reasons stated above. This means that your conversion operator is to an invalid type.
Since you don't define it as explicit, the conversion operator (To an invalid type) will be used to try and match it to the function parameters if they don't already match. Obviously this will finally instantiate the invalid type, so it will throw a compile time error.
My guess is that iostream includes string, which defines std::operator== for strings.
Here's an example without the std namespace: https://godbolt.org/z/-wlAmv
// Avoid including headers for testing without std::
template<class T> struct is_const { static constexpr const bool value = false; } template<class T> struct is_const<const T> { static constexpr const bool value = true; }
namespace with_another_equals {
struct T {};
bool operator==(const T&, const T&) {
return true;
}
}
namespace ns {
template<class T>
struct wrapper {
using invalid_wrapper = wrapper<typename T::invalid>;
operator invalid_wrapper() {}
};
template<class T>
bool operator==(const wrapper<T>&, const wrapper<T>&) {
return true;
}
}
template<class T>
struct with_invalid {
static_assert(!is_const<T>::value, "Invalid if const");
using invalid = with_invalid<const T>;
};
template<class T>
void test() {
using wrapped = ns::wrapper<with_invalid<T>>;
wrapped a;
wrapped b;
bool x = operator==(a, b);
bool y = ns::operator==(a, b);
}
template void test<int*>();
// Will compile if this line is commented out
template void test<with_another_equals::T>();
Note that just declaring operator const_iterator() should instantiate the type. But it doesn't because it is within templates. My guess is that it is optimised out (where it does compile because it's unused) before it can be checked to show that it can't compile (It doesn't even warn with -Wall -pedantic that it doesn't have a return statement in my example).

template function taking cv::Point_<T> as parameter won't compile

I'm trying to write a generic function to serialize to string a std::vector<cv::Point_<T>> and I want this to work for both cv::Point2i and cv::Point2f (both are typedefs of cv::Point_<T> with a specific T).
The function looks like this:
template<typename T>
int SVIniFile::write(const std::string& section,
const std::string& key,
std::vector<cv::Point_<T>>& points)
{
std::ostringstream os;
if (points.empty())
{
return SUCCESS;
}
for (size_t j = 0; j < points.size(); j++)
{
os << points[j].x << " " << points[j].y;
if (j < points.size() - 1)
{
os << " ";
}
}
write(section, key, os.str()); // do the writing of os.str() in the right `section` at `key`
return SUCCESS; // function that writes a string into an ini file
}
Trying to compile this throws an "Unrecognizable template declaration/definition" error. Investigating on the error (full compiler output is below), I found this question, which however doesn't seem related to my case, and this question, the answer of which I don't understand.
I'm very new to template programming and I suspect the error is caused by the fact that I'm using as template parameter the type that is itself a template parameter of one of the parameters. Could anyone point me in the right direction and possibly expand a bit on why the compiler can't build this?
This is what the compiler produces as error output in every file where my header is included:
1>svinifile.h(640): error C4430: missing type specifier - int assumed.
Note: C++ does not support default-int 1>svinifile.h(640): error
C2988: unrecognizable template declaration/definition
1>svinifile.h(640): error C2143: syntax error: missing ',' before '&'
line 640 is the one right after the template<typename T> in the function definition I show above.
Just to be explicit, cv::Point_<T> i OpenCV's 2D point type defined in types.hpp as:
namespace cv
{
// ...
template<typename _Tp> class Point_
{
public:
typedef _Tp value_type;
//! default constructor
Point_();
Point_(_Tp _x, _Tp _y);
Point_(const Point_& pt);
Point_(Point_&& pt) CV_NOEXCEPT;
Point_(const Size_<_Tp>& sz);
Point_(const Vec<_Tp, 2>& v);
Point_& operator = (const Point_& pt);
Point_& operator = (Point_&& pt) CV_NOEXCEPT;
//! conversion to another data type
template<typename _Tp2> operator Point_<_Tp2>() const;
//! conversion to the old-style C structures
operator Vec<_Tp, 2>() const;
//! dot product
_Tp dot(const Point_& pt) const;
//! dot product computed in double-precision arithmetics
double ddot(const Point_& pt) const;
//! cross-product
double cross(const Point_& pt) const;
//! checks whether the point is inside the specified rectangle
bool inside(const Rect_<_Tp>& r) const;
_Tp x; //!< x coordinate of the point
_Tp y; //!< y coordinate of the point
};
typedef Point_<int> Point2i;
typedef Point_<int64> Point2l;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;
typedef Point2i Point;
}
Since there's nothing wrong with the code shown, the problem must be with some code you have not shown. It's probably something very simple, like a missing or out-of-order #include.
You should try to create a Minimal, Complete, and Verifiable example. You'll likely find the problem while doing it.
For example, this compiles just fine on VS 2017:
#include <vector>
namespace cv {
template<typename _Tp> class Point_ {};
typedef Point_<int> Point2i;
}
class SVIniFile {
public:
template<typename T>
int write(
const std::string& section,
const std::string& key,
std::vector<cv::Point_<T>>& points);
};
template<typename T>
int SVIniFile::write(
const std::string& section,
const std::string& key,
std::vector<cv::Point_<T>>& points) {
return 0;
}
int main() {
SVIniFile svIniFile;
std::vector<cv::Point2i> points;
svIniFile.write("abc", "def", points);
return 0;
}

passing const this to function accepting const pointer is not const-correct?

I have a class template Foo with the following member function:
bool contains(const T& item) const
I have instantiated this with a pointer type: Foo<Bar*>, leading me to expect that the member function will now have the following signature:
bool contains(const Bar*& item) const
In a const Bar member function, I attempt to pass this to Foo<Bar*>::contains:
bool Bar::func(const Foo<Bar*>& foo) const
{
return foo.contains(this);
}
This fails to compile, with the following error:
error: invalid conversion from ‘const Bar*’ to ‘Bar*’
Question:
Why is my const T& parameter not const-correct?
What signature for Foo<T>::contains(...) const is required to allow calling with this to compile?
Full example:
#include <vector>
#include <algorithm>
template<typename T>
struct Foo
{
bool contains(const T& item) const
{
return false;
}
};
struct Bar
{
bool func(const Foo<Bar*>& foo) const
{
return foo.contains(this);
}
};
Error output:
scratch/main.cpp:17:33: error: invalid conversion from ‘const Bar*’ to ‘Bar*’ [-fpermissive]
return foo.contains(this);
^
scratch/main.cpp:7:10: note: initializing argument 1 of ‘bool Foo<T>::contains(const T&) const [with T = Bar*]’
bool contains(const T& item) const
I have instantiated this with a pointer type: Foo<Bar*>, leading me
to expect that the member function will now have the following
signature:
bool contains(const Bar*& item) const
That's where the problem is. When T = Bar*, the expression
bool contains(const T& item) const
Will actually compile to
bool contains(Bar * const & item) const
That is, a reference-to-a-const-pointer-to-Bar.
It makes sense of you think about it: you want T to be const, and then you want a reference to that.
If you want to apply the const in the usual "intended" way (though this might cause some surprises for seasoned C++ programmers), you can declare your container and member function in the following way:
template <class T>
class Container {
public:
using const_bare_type = typename std::conditional<
std::is_pointer<T>::value,
typename std::remove_pointer<T>::type const*,
const T>::type;
bool contains(const const_bare_type& item);
};
Compiler alerts about wrong line, you must write:
bool func(const Foo<const Bar*>& foo) const
I.e. const Bar* in template parameter, because Bar::func receives const Bar * this as its parameter, and cannot convert it to Bar* in template parameter (cannot remove const).