g++: range-based for loop not compile without using namespace std; - c++

The following code
#include <iostream>
#include <string>
using namespace std;
template <typename A> std::string to_string(const A& v) {
bool first = true;
std::string res = "{";
for (const auto &x : v) {
if (!first) {
res += ", ";
}
first = false;
res += to_string(x);
}
res += "}";
return res;
}
void debug_out() { std::cerr << std::endl; }
template <typename Head, typename... Tail> void debug_out(const Head& H, const Tail&... T) {
std::cerr << " " << to_string(H);
debug_out(T...);
}
#define debug(...) std::cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
int main() {
int x = 3;
debug(x);
return 0;
}
complies with GCC 9.3.0 and outputs [x]: 3 when run. However, if the 3rd line using namespace std; is commented out, the code does not compile and the errors are
prog.cc: In instantiation of 'std::string to_string(const A&) [with A = int; std::string = std::__cxx11::basic_string<char>]':
prog.cc:21:32: required from 'void debug_out(const Head&, const Tail& ...) [with Head = int; Tail = {}]'
prog.cc:32:3: required from here
prog.cc:7:3: error: 'begin' was not declared in this scope; did you mean 'std::begin'?
7 | for (const auto &x : v) {
| ^~~
| std::begin
In file included from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/string:54,
from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/locale_classes.h:40,
from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/ios_base.h:41,
from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/ios:42,
from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/ostream:38,
from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/iostream:39,
from prog.cc:1:
/opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/range_access.h:105:37: note: 'std::begin' declared here
105 | template<typename _Tp> const _Tp* begin(const valarray<_Tp>&);
| ^~~~~
prog.cc:7:3: error: 'end' was not declared in this scope; did you mean 'std::end'?
7 | for (const auto &x : v) {
| ^~~
| std::end
In file included from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/string:54,
from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/locale_classes.h:40,
from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/ios_base.h:41,
from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/ios:42,
from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/ostream:38,
from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/iostream:39,
from prog.cc:1:
/opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/range_access.h:107:37: note: 'std::end' declared here
107 | template<typename _Tp> const _Tp* end(const valarray<_Tp>&);
|
I know that a ranged-based for loop is not intended to be used on an integer, and the same code (either with or without using name space std;) does not compile with clang. However, why the statement using namespace std; makes a difference when complied with GCC?
You can check this on wandbox https://wandbox.org/permlink/kp5u1iMYHST83tCa .

The reason is that there exists a method to_string in namespace std. If you rename your method to my_to_string the error message will be independent from the using statement.

Related

what is the way to remove the first element from a std::span<T>?

when reading the document of std::span, I see there is no method to remove the first element from the std::span<T>.
Can you suggest a way to solve my issue?
The large picture of my problem(I asked in another question: How to instantiatiate a std::basic_string_view with custom class T, I got is_trivial_v<_CharT> assert error) is that I would like to have a std::basic_string_view<Token>, while the Token is not a trivial class, so I can't use std::basic_string_view, and someone suggested me to use std::span<Token> instead.
Since the basic_string_view has a method named remove_prefix which remove the first element, while I also need such kinds of function because I would like to use std::span<Token> as a parser input, so the Tokens will be matched, and consumed one by one.
Thanks.
EDIT 2023-02-04
I try to derive a class named Span from std::span, and add the remove_prefix member function, but it looks like I still have build issues:
#include <string_view>
#include <vector>
#include <span>
// derived class, add remove_prefix function to std::span
template<typename T>
class Span : public std::span<T>
{
public:
// Inheriting constructors
using std::span<T>::span;
// add a public function which is similar to std::string_view::remove_prefix
constexpr void remove_prefix(std::size_t n) {
*this = subspan(n);
}
};
struct Token
{
Token(){};
Token(const Token& other)
{
lexeme = other.lexeme;
type = other.type;
}
std::string_view lexeme;
int type;
// equal operator
bool operator==(const Token& other)const {
return (this->lexeme == other.lexeme) ;
}
};
template <typename T>
struct Viewer;
template <>
struct Viewer<Token>
{
using type = Span<Token>; // std::span or derived class
};
template <>
struct Viewer<char>
{
using type = std::string_view;
};
template <typename T> using ViewerT = typename Viewer<T>::type;
template <typename T>
class Parser
{
using v = ViewerT<T>;
};
// a simple parser demo
template <typename Base, typename T>
struct parser_base {
using v = ViewerT<T>;
constexpr auto operator[](v& output) const noexcept;
};
template<typename T>
struct char_ final : public parser_base<char_<T>, T> {
using v = ViewerT<T>;
constexpr explicit char_(const T ch) noexcept
: ch(ch)
{}
constexpr inline bool visit(v& sv) const& noexcept {
if (!sv.empty() && sv.front() == ch) {
sv.remove_prefix(1);
return true;
}
return false;
}
private:
T ch;
};
template <typename Parser, typename T>
constexpr bool parse(Span<T> &input, Parser const& parser) noexcept {
return parser.visit(input);
}
int main()
{
Token kw_class;
kw_class.lexeme = "a";
std::vector<Token> token_stream;
token_stream.push_back(kw_class);
token_stream.push_back(kw_class);
token_stream.push_back(kw_class);
Span<Token> token_stream_view{&token_stream[0], 3};
auto p = char_(kw_class);
parse(token_stream_view, p);
return 0;
}
The build error looks like below:
[ 50.0%] g++.exe -Wall -std=c++20 -fexceptions -g -c F:\code\test_crtp_twoargs\main.cpp -o obj\Debug\main.o
F:\code\test_crtp_twoargs\main.cpp: In member function 'constexpr void Span<T>::remove_prefix(std::size_t)':
F:\code\test_crtp_twoargs\main.cpp:52:17: error: there are no arguments to 'subspan' that depend on a template parameter, so a declaration of 'subspan' must be available [-fpermissive]
52 | *this = subspan(n);
| ^~~~~~~
F:\code\test_crtp_twoargs\main.cpp:52:17: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
F:\code\test_crtp_twoargs\main.cpp: In instantiation of 'constexpr void Span<T>::remove_prefix(std::size_t) [with T = Token; std::size_t = long long unsigned int]':
F:\code\test_crtp_twoargs\main.cpp:113:29: required from 'constexpr bool char_<T>::visit(v&) const & [with T = Token; v = Span<Token>]'
F:\code\test_crtp_twoargs\main.cpp:125:24: required from 'constexpr bool parse(Span<T>&, const Parser&) [with Parser = char_<Token>; T = Token]'
F:\code\test_crtp_twoargs\main.cpp:141:10: required from here
F:\code\test_crtp_twoargs\main.cpp:52:24: error: 'subspan' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
52 | *this = subspan(n);
| ~~~~~~~^~~
F:\code\test_crtp_twoargs\main.cpp:52:24: note: declarations in dependent base 'std::span<Token, 18446744073709551615>' are not found by unqualified lookup
F:\code\test_crtp_twoargs\main.cpp:52:24: note: use 'this->subspan' instead
F:\code\test_crtp_twoargs\main.cpp:52:15: error: no match for 'operator=' (operand types are 'Span<Token>' and 'std::span<Token, 18446744073709551615>')
52 | *this = subspan(n);
| ~~~~~~^~~~~~~~~~~~
F:\code\test_crtp_twoargs\main.cpp:44:7: note: candidate: 'constexpr Span<Token>& Span<Token>::operator=(const Span<Token>&)'
44 | class Span : public std::span<T>
| ^~~~
F:\code\test_crtp_twoargs\main.cpp:44:7: note: no known conversion for argument 1 from 'std::span<Token, 18446744073709551615>' to 'const Span<Token>&'
F:\code\test_crtp_twoargs\main.cpp:44:7: note: candidate: 'constexpr Span<Token>& Span<Token>::operator=(Span<Token>&&)'
F:\code\test_crtp_twoargs\main.cpp:44:7: note: no known conversion for argument 1 from 'std::span<Token, 18446744073709551615>' to 'Span<Token>&&'
Any idea on how to fix this issue?
Also, I don't know how to make a general parse function:
template <typename Parser, typename T>
constexpr bool parse(Span<T> &input, Parser const& parser) noexcept {
return parser.visit(input);
}
Currently, the first argument of the parse should be a Viewer like type?
EDIT2023-02-05
Change the function as below, the above code can build correctly. This is from Benjamin Buch's answer.
constexpr void remove_prefix(std::size_t n) {
auto& self = static_cast<std::span<T>&>(*this);
self = self.subspan(n);
}
There is still one thing remains: How to generalize the parse function to accept both input types of std::string_view and Span<Token>?
If I change the parse function to this:
template <typename Parser, typename T>
constexpr bool parse(ViewerT<T> &input, Parser const& parser) noexcept {
return parser.visit(input);
}
I got such compile error:
[ 50.0%] g++.exe -Wall -std=c++20 -fexceptions -g -c F:\code\test_crtp_twoargs\main.cpp -o obj\Debug\main.o
F:\code\test_crtp_twoargs\main.cpp: In function 'int main()':
F:\code\test_crtp_twoargs\main.cpp:143:24: error: no matching function for call to 'parse(Span<Token>&, char_<Token>&)'
143 | bool result = parse(token_stream_view, p);
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~
F:\code\test_crtp_twoargs\main.cpp:125:16: note: candidate: 'template<class Parser, class T> constexpr bool parse(ViewerT<T>&, const Parser&)'
125 | constexpr bool parse(ViewerT<T> &input, Parser const& parser) noexcept {
| ^~~~~
F:\code\test_crtp_twoargs\main.cpp:125:16: note: template argument deduction/substitution failed:
F:\code\test_crtp_twoargs\main.cpp:143:24: note: couldn't deduce template parameter 'T'
143 | bool result = parse(token_stream_view, p);
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~
Any ideas?
Thanks.
BTW: I have to explicitly instantiation of the parse function call like:
bool result = parse<decltype(p), Token>(token_stream_view, p);
to workaround this issue.
Call subspan with 1 as only (template) argument to get a new span, which doesn't contain the first element.
If you use a span with a static extend, you need a new variable because the data type changes by subspan.
#include <string_view>
#include <iostream>
#include <span>
int main() {
std::span<char const, 12> text_a("a test-span");
std::cout << std::string_view(text_a) << '\n';
std::span<char const, 10> text_b = text_a.subspan<2>();
std::cout << std::string_view(text_b) << '\n';
}
If you have a dynamic extend, you can assign the result to the original variable.
#include <string_view>
#include <iostream>
#include <span>
int main() {
std::span<char const> text("a test-span");
std::cout << std::string_view(text) << '\n';
text = text.subspan(2);
std::cout << std::string_view(text) << '\n';
}
The implementation of a modifying inplace subspan version is only possible for spans with a dynamic extend. It can be implemented as a free function.
#include <string_view>
#include <iostream>
#include <span>
template <typename T>
constexpr void remove_front(std::span<T>& self, std::size_t const n) noexcept {
self = self.subspan(n);
}
int main() {
std::span<char const> text("a test-span");
std::cout << std::string_view(text) << '\n';
remove_front(text, 2);
std::cout << std::string_view(text) << '\n';
}
You can use your own spans derived from std::span if you prefer the dot-call.
#include <string_view>
#include <iostream>
#include <span>
template <typename T>
struct my_span: std::span<T> {
using std::span<T>::span;
constexpr void remove_front(std::size_t const n) noexcept {
auto& self = static_cast<std::span<T>&>(*this);
self = self.subspan(n);
}
};
int main() {
my_span<char const> my_text("a test-span");
std::cout << std::string_view(my_text) << '\n';
my_text.remove_front(2);
std::cout << std::string_view(my_text) << '\n';
}
You can also write a wrapper class to call via dot syntax. This way you can additionally implement cascadable modification calls by always returning the a reference modifier class.
#include <string_view>
#include <iostream>
#include <span>
template <typename T>
class span_modifier {
public:
constexpr span_modifier(std::span<T>& span) noexcept: span_(span) {}
constexpr span_modifier& remove_front(std::size_t const n) noexcept {
span_ = span_.subspan(n);
return *this;
}
private:
std::span<T>& span_;
};
template <typename T>
constexpr span_modifier<T> modify(std::span<T>& span) noexcept {
return span;
}
int main() {
std::span<char const> text("a test-span");
std::cout << std::string_view(text) << '\n';
modify(text).remove_front(2).remove_front(5);
std::cout << std::string_view(text) << '\n';
}
Note I use the template function modify to create an object of the wrapper class, because the names of classes cannot be overloaded. Therefore class names should always be a bit more specific. The function modify can also be overloaded for other data types, which then return a different wrapper class. This results in a simple intuitive and consistent interface for modification wrappers.
You can write remove_prefix of your version,
template <typename T>
constexpr void remove_prefix(std::span<T>& sp, std::size_t n) {
sp = sp.subspan(n);
}
Demo

Build rtree with boost::geometry results in errors

I wrote this small program, following the boost documentation, but I get pages of errors when building it.
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <iostream>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
typedef bg::model::d2::point_xy<double> point_2d;
class Foo
{
public:
point_2d position;
Foo(double x, double y) : position(x, y) {}
auto get() const { return position; }
};
int main()
{
bgi::rtree<Foo, bgi::quadratic<16>> rtree;
rtree.insert(Foo(1.0, 2.0));
rtree.insert(Foo(3.0, 4.0));
rtree.insert(Foo(5.0, 6.0));
rtree.insert(Foo(7.0, 8.0));
// Define a search box with a certain distance from a given point
point_2d search_point(0.0, 0.0);
double search_distance = 5.0;
point_2d lower_left(search_point.x() - search_distance, search_point.y() - search_distance);
point_2d upper_right(search_point.x() + search_distance, search_point.y() + search_distance);
bg::model::box<point_2d> search_box(lower_left, upper_right);
// Use the rtree to search for instances of Foo within the search box
std::vector<Foo> result;
rtree.query(bgi::intersects(search_box), std::back_inserter(result));
// Print the results
std::cout << "Found " << result.size() << " instances of Foo within the search box" << std::endl;
for (const auto& foo : result)
std::cout << "Foo at position (" << foo.position.x() << ", " << foo.position.y() << ")" << std::endl;
}
Here is the build:
clang++ --std=c++17 tree.cpp -lboost-geometry 2>&1 | head -n50
In file included from tree.cpp:1:
In file included from /usr/include/boost/geometry/index/rtree.hpp:49:
/usr/include/boost/geometry/index/indexable.hpp:64:5: error: no matching function for call to 'assertion_failed'
BOOST_MPL_ASSERT_MSG(
^~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/mpl/assert.hpp:454:51: note: expanded from macro 'BOOST_MPL_ASSERT_MSG'
# define BOOST_MPL_ASSERT_MSG( c, msg, types_ ) \
^
/usr/include/boost/mpl/assert.hpp:440:9: note: expanded from macro '\
BOOST_MPL_ASSERT_MSG_IMPL'
boost::mpl::assertion_failed<(c)>( BOOST_PP_CAT(mpl_assert_arg,counter)::assert_arg() ) \
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/mpl/assert.hpp:60:58: note: expanded from macro '\
BOOST_MPL_AUX_ASSERT_CONSTANT'
# define BOOST_MPL_AUX_ASSERT_CONSTANT(T, expr) enum { expr }
^~~~
/usr/include/boost/geometry/index/indexable.hpp:351:7: note: in instantiation of template class 'boost::geometry::index::detail::indexable<Foo, false>' requested here
: detail::indexable<Value>
^
/usr/include/boost/geometry/index/detail/translator.hpp:46:14: note: in instantiation of template class 'boost::geometry::index::indexable<Foo>' requested here
: public IndexableGetter
^
/usr/include/boost/geometry/index/detail/translator.hpp:74:22: note: in instantiation of template class 'boost::geometry::index::detail::translator<boost::geometry::index::indexable<Foo>, boost::geometry::index::equal_to<Foo> >' requested here
typedef typename IndexableGetter::result_type type;
^
/usr/include/boost/geometry/index/detail/translator.hpp:82:22: note: in instantiation of template class 'boost::geometry::index::detail::result_type<boost::geometry::index::detail::translator<boost::geometry::index::indexable<Foo>, boost::geometry::index::equal_to<Foo> > >' requested here
typename result_type<IndexableGetter>::type
^
/usr/include/boost/geometry/index/rtree.hpp:177:37: note: in instantiation of template class 'boost::geometry::index::detail::indexable_type<boost::geometry::index::detail::translator<boost::geometry::index::indexable<Foo>, boost::geometry::index::equal_to<Foo> > >' requested here
typedef typename index::detail::indexable_type<
^
tree.cpp:27:41: note: in instantiation of template class 'boost::geometry::index::rtree<Foo, boost::geometry::index::quadratic<16, 4>, boost::geometry::index::indexable<Foo>, boost::geometry::index::equal_to<Foo>, boost::container::new_allocator<Foo> >' requested here
bgi::rtree<Foo, bgi::quadratic<16>> rtree;
^
/usr/include/boost/mpl/assert.hpp:83:5: note: candidate function template not viable: no known conversion from 'boost::mpl::failed ************(boost::geometry::index::detail::indexable<Foo, false>::NOT_VALID_INDEXABLE_TYPE::************)(Foo)' to 'typename assert<false>::type' (aka 'mpl_::assert<false>') for 1st argument
int assertion_failed( typename assert<C>::type );
^
In file included from tree.cpp:1:
In file included from /usr/include/boost/geometry/index/rtree.hpp:28:
In file included from /usr/include/boost/geometry/algorithms/detail/comparable_distance/interface.hpp:23:
In file included from /usr/include/boost/geometry/geometries/concepts/check.hpp:28:
In file included from /usr/include/boost/geometry/geometries/concepts/box_concept.hpp:23:
In file included from /usr/include/boost/geometry/core/access.hpp:25:
In file included from /usr/include/boost/geometry/core/coordinate_type.hpp:20:
/usr/include/boost/geometry/core/point_type.hpp:45:5: error: no matching function for call to 'assertion_failed'
BOOST_MPL_ASSERT_MSG
^~~~~~~~~~~~~~~~~~~~
/usr/include/boost/mpl/assert.hpp:454:51: note: expanded from macro 'BOOST_MPL_ASSERT_MSG'
# define BOOST_MPL_ASSERT_MSG( c, msg, types_ ) \
Foo is not an indexable type. Meaning, mainly, that rtree doesn't know what geometry to index it by.
Let's make an IndexableGetter:
struct ByPos {
using result_type = point_2d;
result_type const& operator()(Foo const& f) const { return f.position; }
};
Now you can use it:
Live On Coliru
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <iostream>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
using point_2d = bg::model::d2::point_xy<double> ;
using box = bg::model::box<point_2d>;
struct Foo {
point_2d position;
Foo(double x, double y) : position(x, y) {}
auto get() const { return position; }
struct ByPos {
using result_type = point_2d;
result_type const& operator()(Foo const& f) const { return f.position; }
};
};
auto intersecting(auto const& search, auto const& tree) {
std::vector<std::reference_wrapper<Foo const>> result;
tree.query(bgi::intersects(search), back_inserter(result));
return result;
}
int main() {
bgi::rtree<Foo, bgi::quadratic<16>, Foo::ByPos> rtree;
rtree.insert({1.0, 2.0});
rtree.insert({3.0, 4.0});
rtree.insert({5.0, 6.0});
rtree.insert({7.0, 8.0});
// box with given distance from center
auto makebox = [&](double d, point_2d c = {}) {
return box{{c.x() - d, c.y() - d}, {c.x() + d, c.y() + d}};
};
auto key = makebox(5.0);
std::cout << "Within " << bg::dsv(key) << ":\n";
for (Foo const& foo : intersecting(key, rtree))
std::cout << " - at " << bg::dsv(foo.position) << "\n";
}
Prints
Within ((-5, -5), (5, 5)):
- at (1, 2)
- at (3, 4)

scoped_allocator_adaptor seems to require allocator to be default constructed

In my experiments with scoped_allocator_adaptor, I'm trying to pass the allocator obtained from main(..) into S1's constructor (more generally there would be multiple different types within S1 that would all use the allocator that was made available in the constructor). However, I get the compile error below indicating that the allocator should be default constructible. Can someone help explain why this might be the case? Is there some conversion taking place leading to the default constructed version of the allocator being needed?
#include <iostream>
#include <cassert>
#include <vector>
#include <scoped_allocator>
// Move allocator and container aliases into namepsace
namespace custom
{
template <typename T>
struct MyAlloc
{
using value_type = T;
MyAlloc(const std::string &scope) noexcept : _scope(scope) {}
// Rebinding allocatos to different type
template <class U>
MyAlloc(const MyAlloc<U> & other) noexcept : _scope(other._scope) {}
// Allow for move operations to be noexcept
//using is_always_equal = std::true_type;
value_type* allocate(std::size_t n) noexcept
{
std::cout << "Allocating " << n << " objects within " << _scope << " from " << __PRETTY_FUNCTION__ << std::endl;
return static_cast<value_type*>(::operator new (n*sizeof(value_type)));
}
void deallocate(value_type* p, std::size_t n) noexcept
{
std::cout << "Deallocating " << n << " objects within " << _scope << " from " << __PRETTY_FUNCTION__ << std::endl;
::operator delete(p);
}
std::string _scope;
};
// Allocators compare equal to enable one allocator to de-allocate memory
// from another
template <typename T>
bool operator==(const MyAlloc<T> &x1, const MyAlloc<T> &x2) noexcept
{
return true;
}
template <typename T>
bool operator!=(const MyAlloc<T> &x1, const MyAlloc<T> &x2) noexcept
{
return !(x1 == x2);
}
template <typename T>
using allocator = std::scoped_allocator_adaptor<MyAlloc<T>>;
template <typename T> // adaptor to propagate
using vector = std::vector<T, allocator<T>>;
template <typename T>
using bstr = std::basic_string<T, std::char_traits<T>, allocator<T>>;
using string = bstr<char>;
}
struct S1
{
using allocator_type = custom::allocator<std::byte>;
S1(allocator_type alloc) : str("This is a very long string indeed..", std::allocator_traits<allocator_type>::rebind_alloc<char>(alloc))
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
S1(const S1 &other, allocator_type al) : str(other.str, std::allocator_traits<allocator_type>::rebind_alloc<char>(al))
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
custom::string str;
};
int main()
{
custom::allocator<std::byte> sc{"scope"};
custom::vector<S1> cv{sc};
// cv.emplace_back();
}
Compile error:
/usr/include/c++/10/scoped_allocator: In instantiation of ‘std::scoped_allocator_adaptor<_OuterAlloc, _InnerAllocs>::scoped_allocator_adaptor() [with _OuterAlloc = custom::MyAlloc<S1>; _InnerAllocs = {}]’:
/usr/include/c++/10/bits/stl_vector.h:626:35: required from here
/usr/include/c++/10/scoped_allocator:304:60: error: no matching function for call to ‘custom::MyAlloc<S1>::MyAlloc()’
304 | scoped_allocator_adaptor() : _OuterAlloc(), _M_inner() { }
| ^
d2.cc:17:9: note: candidate: ‘template<class U> custom::MyAlloc<T>::MyAlloc(const custom::MyAlloc<U>&) [with U = U; T = S1]’
17 | MyAlloc(const MyAlloc<U> & other) noexcept : _scope(other._scope) {}
| ^~~~~~~
d2.cc:17:9: note: template argument deduction/substitution failed:
In file included from d2.cc:4:
/usr/include/c++/10/scoped_allocator:304:60: note: candidate expects 1 argument, 0 provided
304 | scoped_allocator_adaptor() : _OuterAlloc(), _M_inner() { }
| ^
d2.cc:13:9: note: candidate: ‘custom::MyAlloc<T>::MyAlloc(const string&) [with T = S1; std::string = std::__cxx11::basic_string<char>]’
13 | MyAlloc(const std::string &scope) noexcept : _scope(scope) {}
| ^~~~~~~
d2.cc:13:9: note: candidate expects 1 argument, 0 provided
d2.cc:10:12: note: candidate: ‘custom::MyAlloc<S1>::MyAlloc(const custom::MyAlloc<S1>&)’
10 | struct MyAlloc
| ^~~~~~~
d2.cc:10:12: note: candidate expects 1 argument, 0 provided
d2.cc:10:12: note: candidate: ‘custom::MyAlloc<S1>::MyAlloc(custom::MyAlloc<S1>&&)’
d2.cc:10:12: note: candidate expects 1 argument, 0 provided
This line: custom::vector<S1> cv{sc}; is the problem.
Because you've used brackets, it's trying to call vectors initializer-list constructor, which has an optional parameter which is an allocator - which it default constructs.
See the last two constructors in the list on cppreference
If you change that line to custom::vector<S1> cv(sc); it will compile w/o error.

Passing const T& as this to a constexpr member function

I am trying to fix some library code where a boiled-down minimal version looks like this:
#include <iostream>
template <typename RangeT>
struct formatter {
constexpr void format(const RangeT& values) {
for (auto it = values.begin(), end = values.end(); it != end; ++it) {
std::cout << it << "\n";
}
}
};
template <typename RangeT, typename Formatter>
struct type_erased {
static void format(const void* arg) {
Formatter f;
f.format(*static_cast<const RangeT*>(arg));
}
};
struct view {
int count_;
constexpr View(int count) : count_(count) {}
constexpr int
begin() { return 0; }
constexpr int
end() { return -1; }
};
int
main()
{
View view(5);
void* ptr = static_cast<void*>(&view);
type_erased<View, formatter<View>>::format(ptr);
}
The above code does not compile in GCC since:
../src/view.cpp: In instantiation of ‘constexpr void formatter<RangeT>::format(const RangeT&) [with RangeT = View]’:
../src/view.cpp:21:9: required from ‘static void type_erased<RangeT, Formatter>::format(const void*) [with RangeT = View; Formatter = formatter<View>]’
../src/view.cpp:43:41: required from here
../src/view.cpp:11:15: error: passing ‘const View’ as ‘this’ argument discards qualifiers [-fpermissive]
11 | for (auto it = values.begin(), end = values.end(); it != end; ++it) {
| ^~
../src/view.cpp:31:5: note: in call to ‘constexpr int View::begin()’
31 | begin() { return 0; }
| ^~~~~
../src/view.cpp:11:36: error: passing ‘const View’ as ‘this’ argument discards qualifiers [-fpermissive]
11 | for (auto it = values.begin(), end = values.end(); it != end; ++it) {
| ^~~
../src/view.cpp:34:5: note: in call to ‘constexpr int View::end()’
34 | end() { return -1; }
What are the rules regarding this in constexpr member function? Is it subject to the rules specified for function parameters or are there special constraints?
How would I go about fixing this error? If it would only be the formatter struct I would use RangeT&& and std::move since views are by definition copyable in O(1) as far as I know. I don't know how to do that with the type erasure step in the mix though...
Thanks in advance,
Richard
I don't think this has anything to do with constexpr.
You have a reference to const RangeT, and you're trying to invoke non-const member functions on it (begin() and end()).
Provide const overloads (and/or cbegin()/cend() variants) if you want to permit that.
In your code as begin and end are not const functions the this pointer can't point to a const object without "discarding qualifiers".
By making the functions const then the this pointer can point to a const object.
https://en.cppreference.com/w/cpp/language/member_functions#const-.2C_volatile-.2C_and_ref-qualified_member_functions
https://en.cppreference.com/w/cpp/language/this
https://godbolt.org/z/3_wKh9

use of boost::hana::eval_if_t before deduction of auto

A code snippet says more than a couple of paragraphs:
#include <boost/hana/fwd/eval_if.hpp>
#include <boost/hana/core/is_a.hpp>
#include <iostream>
#include <functional>
using namespace boost::hana;
template<class arg_t>
decltype(auto) f2(arg_t const& a)
{
constexpr bool b = is_a<std::reference_wrapper<std::string>,
arg_t>;
auto wrapper_case = [&a](auto _) -> std::string&
{ return _(a).get(); };
auto default_case = [&a]() -> arg_t const&
{ return a; };
return eval_if(b, wrapper_case, default_case);
}
int main()
{
int a = 3;
std::string str = "hi!";
auto str_ref = std::ref(str);
std::cout << f2(a) << ", " << f2(str) << ", " << f2(str_ref)
<< std::endl;
}
The compiler error is:
$> g++ -std=c++14 main.cpp
main.cpp: In instantiation of ‘decltype(auto) f2(const arg_t&) [with arg_t = int]’:
main.cpp:42:22: required from here
main.cpp:31:19: error: use of ‘constexpr decltype(auto) boost::hana::eval_if_t::operator()(Cond&&, Then&&, Else&&) const [with Cond = const bool&; Then = f2(const arg_t&) [with arg_t = int]::<lambda(auto:1)>&; Else = f2(const arg_t&) [with arg_t = int]::<lambda(auto:2)>&]’ before deduction of ‘auto’
return eval_if(b, wrapper_case, default_case);
~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There's no recursion, I use gcc-6.0.2 which presumably has solved some bugs about decltype(auto) and has a full working C++14 implementation, and also fits the boost::hana requirements, so, my error must be in my implementation but I don't know what is the error about.
NOTE: clang++ 3.8.0 throws a similar compiler error.
First, in case the path doesn't make it clear, boost/hana/fwd/eval_if.hpp is but a forward declaration. If you want to use it in earnest, you need to include the whole thing, i.e., boost/hana/eval_if.hpp. That's the cause of the original error.
Then, this bool is wrong:
constexpr bool b = is_a<std::reference_wrapper<std::string>,
arg_t>;
Coercing it to bool means that the type no longer carries the value information. Use auto.