The following code https://godbolt.org/z/X0na5H fails to compile the rvalue version of the following code. I've used the BOOST_FOREACH extensibility guidelines I found here
In short I can't seem to get boost_foreach working with noncopyabe rvalues. Is this even possible?
#include <boost/optional.hpp>
#include <boost/foreach.hpp>
#include <vector>
struct IdentityOp : std::vector<int>, boost::noncopyable {
IdentityOp(std::vector<int> && v):std::vector<int>(std::move(v)){}
};
namespace boost { namespace foreach
{
template <>
struct is_noncopyable< IdentityOp >
: mpl::true_
{
};
}}
#define BGS_TEST_LVALUE
// At global scope...
inline boost::mpl::true_ *
boost_foreach_is_noncopyable( IdentityOp *&, boost::foreach::tag )
{
return 0;
}
int main(){
std::vector<int> v;
#ifdef BGS_TEST_LVALUE
// LVALUE VERSION
IdentityOp op(std::move(v));
BOOST_FOREACH(const auto & a, op)
#else
// RVALUE VERSION
BOOST_FOREACH(const auto & a, IdentityOp(std::move(v)))
#endif
{}
}
shows the problem. If I define BGS_TEST_LVALUE then the code compiles. If I don't define it I get the error.
In file included from <source>:2:
/celibs/boost_1_70_0/boost/foreach.hpp: In instantiation of 'boost::foreach_detail_::auto_any<T> boost::foreach_detail_::contain(const T&, mpl_::true_*) [with T = IdentityOp; mpl_::true_ = mpl_::bool_<true>]':
<source>:34:5: required from here
/celibs/boost_1_70_0/boost/foreach.hpp:632:25: error: use of deleted function 'boost::foreach_detail_::auto_any<IdentityOp>::auto_any(boost::foreach_detail_::auto_any<IdentityOp>&&)'
632 | return auto_any<T>(t);
| ^
/celibs/boost_1_70_0/boost/foreach.hpp:253:8: note: 'boost::foreach_detail_::auto_any<IdentityOp>::auto_any(boost::foreach_detail_::auto_any<IdentityOp>&&)' is implicitly deleted because the default definition would be ill-formed:
253 | struct auto_any : auto_any_base
| ^~~~~~~~
/celibs/boost_1_70_0/boost/foreach.hpp:253:8: error: call of overloaded 'IdentityOp(IdentityOp)' is ambiguous
<source>:8:5: note: candidate: 'IdentityOp::IdentityOp(std::vector<int>&&)'
8 | IdentityOp(std::vector<int> && v):std::vector<int>(std::move(v)){}
| ^~~~~~~~~~
<source>:7:9: note: candidate: 'IdentityOp::IdentityOp(const IdentityOp&)' <deleted>
7 | struct IdentityOp : std::vector<int>, boost::noncopyable {
| ^~~~~~~~~~
<source>:7:9: note: candidate: 'IdentityOp::IdentityOp(IdentityOp&&)' <deleted>
In file included from <source>:2:
/celibs/boost_1_70_0/boost/foreach.hpp: In instantiation of 'boost::foreach_detail_::auto_any<T>::auto_any(const T&) [with T = IdentityOp]':
/celibs/boost_1_70_0/boost/foreach.hpp:632:12: required from 'boost::foreach_detail_::auto_any<T> boost::foreach_detail_::contain(const T&, mpl_::true_*) [with T = IdentityOp; mpl_::true_ = mpl_::bool_<true>]'
<source>:34:5: required from here
/celibs/boost_1_70_0/boost/foreach.hpp:256:15: error: use of deleted function 'IdentityOp::IdentityOp(const IdentityOp&)'
256 | : item(t)
| ^
<source>:7:9: note: 'IdentityOp::IdentityOp(const IdentityOp&)' is implicitly deleted because the default definition would be ill-formed:
7 | struct IdentityOp : std::vector<int>, boost::noncopyable {
| ^~~~~~~~~~
<source>:7:9: error: use of deleted function 'boost::noncopyable_::noncopyable::noncopyable(const boost::noncopyable_::noncopyable&)'
In file included from /celibs/boost_1_70_0/boost/noncopyable.hpp:15,
from /celibs/boost_1_70_0/boost/foreach.hpp:72,
from <source>:2:
/celibs/boost_1_70_0/boost/core/noncopyable.hpp:49:7: note: declared here
49 | noncopyable( const noncopyable& ) = delete;
| ^~~~~~~~~~~
Compiler returned: 1
https://godbolt.org/z/X0na5H
Related
Compare the following case when I have a class object that takes a vector. The non-deduced parameter T can be substituted fine with the default template argument:
#include <vector>
template <typename T = int>
struct container
{
container(std::vector<T> vec) {}
};
int main()
{
container C = std::vector{1,2,3,4,5};
}
This is not the case for my class which is a bit more complicated (CompilerExplorer):
#include <cstdio>
#include <initializer_list>
#include <variant>
template <size_t> struct obj;
template<size_t Vs>
using val = std::variant<std::monostate, int, struct obj<Vs>>;
template <size_t Vs = 0>
struct obj
{
obj() = default;
obj(std::initializer_list<val<Vs>> init) {
printf("initializer of object called, Vs = %d\n", Vs);
}
};
template <size_t Vs = 0>
struct container : public obj<Vs>
{
container(obj<0> init) {}
};
int main()
{
container<5> some_container = obj{1,2,5,2,obj{1,2,33},2,2};
}
This fails with the following error:
<source>: In function 'int main()':
<source>:29:57: error: class template argument deduction failed:
29 | container<5> some_container = obj{1,2,5,2,obj{1,2,33},2,2};
| ^
<source>:29:57: error: no matching function for call to 'obj(int, int, int)'
<source>:14:5: note: candidate: 'template<long unsigned int Vs> obj(std::initializer_list<std::variant<std::monostate, int, obj<Vs> > >)-> obj<<anonymous> >'
14 | obj(std::initializer_list<val<Vs>> init) {
| ^~~
But it works when I supplement the template specialization obj<0> in the instantiation of the container (in main). Any ideas why this doesn't work for my class and how I can fix it? I don't want to force the user to specify the template each time.
This problem already exists in the simpler case of just
auto o = obj{1,2,33};
which yields this error:
<source>:29:24: error: class template argument deduction failed:
29 | auto o = obj{1,2,33};
| ^
<source>:29:24: error: no matching function for call to 'obj(int, int, int)'
<source>:14:5: note: candidate: 'template<long unsigned int Vs> obj(std::initializer_list<std::variant<std::monostate, int, obj<Vs> > >)-> obj<<anonymous> >'
14 | obj(std::initializer_list<val<Vs>> init) {
| ^~~
<source>:14:5: note: template argument deduction/substitution failed:
<source>:29:24: note: mismatched types 'std::initializer_list<std::variant<std::monostate, int, obj<Vs> > >' and 'int'
29 | auto o = obj{1,2,33};
So, the compiler is unable to deduce, that the three ints should be an initializer list. If you add extra braces around them, the compiler recognizes that this should actually be a single list argument instead of three separate ones and it works:
auto o = obj{{1,2,33}};
This also carries over to the more complicated case:
container some_container = obj{{1,2,5,2,obj{{1,2,33}},2,2}};
OrderProcessor::ProcessRange function in the code below accepts a range as an argument and iterates over it. When I try to call it with a range constructed with std::views::filter it does not compile, but when I copy and paste OrderProcessor::ProcessRange function implementation into the code it compiles:
#include <iostream>
#include <ranges>
#include <vector>
namespace data
{
struct Order
{
};
}
namespace app
{
template <class R, class Value>
concept range_over = std::ranges::range<R> &&
std::same_as<std::ranges::range_value_t<R>, Value>;
class OrderProcessor
{
public:
void Process(const data::Order&) {}
template <range_over<data::Order> Range>
void ProcessRange(const Range& range)
{
for (const data::Order& order : range)
{
Process(order);
}
}
};
}
int main()
{
using namespace app;
std::vector<data::Order> sample_orders;
auto range = sample_orders | std::views::filter([](const data::Order&) -> bool { return true; });
OrderProcessor processor;
processor.ProcessRange(range); //-does not compile
//But the following loop compiles:
//for (const data::Order& order : range)
//{
// processor.Process(order);
//}
}
it also compiles if I remove std::views::filter, what can be the difference?
GCC errors:
prog.cc: In instantiation of 'void app::OrderProcessor::ProcessRange(const Range&) [with Range = std::ranges::filter_view<std::ranges::ref_view<std::vector<data::Order> >, main()::<lambda(const data::Order&)> >]' :
prog.cc : 51 : 27 : required from here
prog.cc : 32 : 13 : error : passing 'const std::ranges::filter_view<std::ranges::ref_view<std::vector<data::Order> >, main()::<lambda(const data::Order&)> >' as 'this' argument discards qualifiers[-fpermissive]
32 | for (const data::Order& order : range)
| ^ ~~
In file included from prog.cc : 2 :
/ opt / wandbox / gcc - 11.1.0 / include / c++ / 11.1.0 / ranges : 1307 : 7 : note : in call to 'constexpr std::ranges::filter_view<_Vp, _Pred>::_Iterator std::ranges::filter_view<_Vp, _Pred>::begin() [with _Vp = std::ranges::ref_view<std::vector<data::Order> >; _Pred = main()::<lambda(const data::Order&)>]'
1307 | begin()
| ^ ~~~~
prog.cc : 32 : 13 : error : passing 'const std::ranges::filter_view<std::ranges::ref_view<std::vector<data::Order> >, main()::<lambda(const data::Order&)> >' as 'this' argument discards qualifiers[-fpermissive]
32 | for (const data::Order& order : range)
| ^ ~~
In file included from prog.cc : 2 :
/ opt / wandbox / gcc - 11.1.0 / include / c++ / 11.1.0 / ranges : 1321 : 7 : note : in call to 'constexpr auto std::ranges::filter_view<_Vp, _Pred>::end() [with _Vp = std::ranges::ref_view<std::vector<data::Order> >; _Pred = main()::<lambda(const data::Order&)>]'
1321 | end()
| ^ ~~
You just need to drop the const on the range argument to ProcessOrder(). A range may change when you iterate it - and apparently that's true for the filter view. Perhaps the library or the compiler could have guessed otherwise, but they don't.
Without the const - it compiles: https://godbolt.org/z/MnEczfTjG
Also note that if you make the range variable const to begin with, you'll be in trouble with your loop as well.
I want to search an input range for an element that has a certain value in a member via an accessor.
range-v3 documentation is... thin, but there are sources such as this answer by AFAIK the 2 main range-v3 developers indicates this kind of thing should Just Work, albeit with sort not find.
Given the code, compiled with g++ -std=c++17 against ericniebler/range-v3 release range-v3-0.10.0, using g++.exe (Rev2, Built by MSYS2 project) 9.3.0:
#include <range/v3/algorithm/find.hpp>
#include <vector>
auto
main() -> int
{
struct S {
int i{};
auto get_i() const { return i; }
};
auto const ss = std::vector<S>(10);
ranges::find(ss, 1, &S::get_i);
return 0;
}
I get a spew of errors:
test.cpp: In function 'int main()':
test.cpp:14:31: error: no match for call to '(const ranges::find_fn) (const std::vector<main()::S>&, int, int (main()::S::*)() const)'
14 | ranges::find(ss, 1, &S::get_i);
| ^
In file included from FOO/include/range-v3/range/v3/range_fwd.hpp:24,
from FOO/include/range-v3/range/v3/algorithm/find.hpp:18,
from test.cpp:1:
FOO/include/range-v3/range/v3/detail/config.hpp:618:27: note: candidate: 'template<class I, class S, class V, class P> constexpr concepts::return_t<I, typename std::enable_if<(((input_iterator<I> && sentinel_for<S, I>) && indirect_relation<ranges::equal_to, typename ranges::detail::select_projected_<P>::apply<I>, const V*>) && concepts::detail::CPP_true(concepts::detail::Nil{})), void>::type> ranges::find_fn::operator()(I, S, const V&, P) const'
618 | #define RANGES_FUNC(NAME) operator() RANGES_FUNC_CONST_ /**/
| ^~~~~~~~
FOO/include/range-v3/range/v3/algorithm/find.hpp:47:24: note: in expansion of macro 'RANGES_FUNC'
47 | constexpr auto RANGES_FUNC(find)(I first, S last, V const & val, P proj = P{})
| ^~~~~~~~~~~
FOO/include/range-v3/range/v3/detail/config.hpp:618:27: note: template argument deduction/substitution failed:
618 | #define RANGES_FUNC(NAME) operator() RANGES_FUNC_CONST_ /**/
| ^~~~~~~~
FOO/include/range-v3/range/v3/algorithm/find.hpp:47:24: note: in expansion of macro 'RANGES_FUNC'
47 | constexpr auto RANGES_FUNC(find)(I first, S last, V const & val, P proj = P{})
| ^~~~~~~~~~~
In file included from FOO/include/range-v3/range/v3/iterator/access.hpp:22,
from FOO/include/range-v3/range/v3/iterator/concepts.hpp:30,
from FOO/include/range-v3/range/v3/algorithm/find.hpp:22,
from test.cpp:1:
FOO/include/range-v3/std/detail/associated_types.hpp: In substitution of 'template<bool B, class T> using enable_if_t = typename ranges::detail::enable_if::apply<T> [with bool B = ranges::readable<std::vector<main()::S> >; T = std::vector<main()::S>]':
FOO/include/range-v3/range/v3/iterator/concepts.hpp:561:19: required by substitution of 'template<class I> using apply = ranges::detail::enable_if_t<(bool)(readable<I>), I> [with I = std::vector<main()::S>]'
FOO/include/range-v3/range/v3/algorithm/find.hpp:48:15: required by substitution of 'template<class I, class S, class V, class P> constexpr concepts::return_t<I, typename std::enable_if<(((input_iterator<I> && sentinel_for<S, I>) && indirect_relation<ranges::equal_to, typename ranges::detail::select_projected_<P>::apply<I>, const V*>) && concepts::detail::CPP_true(concepts::detail::Nil{})), void>::type> ranges::find_fn::operator()(I, S, const V&, P) const [with I = std::vector<main()::S>; S = int; V = int (main()::S::*)() const; P = ranges::identity]'
test.cpp:14:31: required from here
FOO/include/range-v3/std/detail/associated_types.hpp:73:15: error: no class template named 'apply' in 'struct ranges::detail::enable_if<false>'
73 | using enable_if_t = typename enable_if<B>::template apply<T>;
| ^~~~~~~~~~~
In file included from FOO/include/range-v3/range/v3/range_fwd.hpp:24,
from FOO/include/range-v3/range/v3/algorithm/find.hpp:18,
from test.cpp:1:
FOO/include/range-v3/range/v3/detail/config.hpp:618:27: note: candidate: 'template<class Rng, class V, class P> constexpr concepts::return_t<typename ranges::detail::if_then<forwarding_range_<R> >::apply<decltype (ranges::_::begin(declval<Rng&>())), ranges::dangling>, typename std::enable_if<((input_range<Rng> && indirect_relation<ranges::equal_to, typename ranges::detail::select_projected_<P1>::apply<decltype (ranges::_::begin(declval<Rng&>()))>, const V*>) && concepts::detail::CPP_true(concepts::detail::Nil{})), void>::type> ranges::find_fn::operator()(Rng&&, const V&, P) const'
618 | #define RANGES_FUNC(NAME) operator() RANGES_FUNC_CONST_ /**/
| ^~~~~~~~
FOO/include/range-v3/range/v3/algorithm/find.hpp:60:24: note: in expansion of macro 'RANGES_FUNC'
60 | constexpr auto RANGES_FUNC(find)(Rng && rng, V const & val, P proj = P{})
| ^~~~~~~~~~~
FOO/include/range-v3/range/v3/detail/config.hpp:618:27: note: template argument deduction/substitution failed:
618 | #define RANGES_FUNC(NAME) operator() RANGES_FUNC_CONST_ /**/
| ^~~~~~~~
FOO/include/range-v3/range/v3/algorithm/find.hpp:60:24: note: in expansion of macro 'RANGES_FUNC'
60 | constexpr auto RANGES_FUNC(find)(Rng && rng, V const & val, P proj = P{})
| ^~~~~~~~~~~
In file included from FOO/include/range-v3/range/v3/iterator/access.hpp:22,
from FOO/include/range-v3/range/v3/iterator/concepts.hpp:30,
from FOO/include/range-v3/range/v3/algorithm/find.hpp:22,
from test.cpp:1:
FOO/include/range-v3/std/detail/associated_types.hpp: In substitution of 'template<bool B, class T> using enable_if_t = typename ranges::detail::enable_if::apply<T> [with bool B = ranges::indirectly_regular_unary_invocable<int (main()::S::*)() const, __gnu_cxx::__normal_iterator<const main()::S*, std::vector<main()::S> > >; T = ranges::detail::projected_<__gnu_cxx::__normal_iterator<const main()::S*, std::vector<main()::S> >, int (main()::S::*)() const>]':
FOO/include/range-v3/range/v3/iterator/concepts.hpp:552:19: required by substitution of 'template<class Proj> template<class I> using apply = ranges::detail::enable_if_t<(bool)(indirectly_regular_unary_invocable<Proj, I>), ranges::detail::projected_<I, Proj> > [with I = __gnu_cxx::__normal_iterator<const main()::S*, std::vector<main()::S> >; Proj = int (main()::S::*)() const]'
FOO/include/range-v3/range/v3/algorithm/find.hpp:61:15: required by substitution of 'template<class Rng, class V, class P> constexpr concepts::return_t<typename ranges::detail::if_then<forwarding_range_<R> >::apply<decltype (ranges::_::begin(declval<Rng&>())), ranges::dangling>, typename std::enable_if<((input_range<Rng> && indirect_relation<ranges::equal_to, typename ranges::detail::select_projected_<P1>::apply<decltype (ranges::_::begin(declval<Rng&>()))>, const V*>) && concepts::detail::CPP_true(concepts::detail::Nil{})), void>::type> ranges::find_fn::operator()(Rng&&, const V&, P) const [with Rng = const std::vector<main()::S>&; V = int; P = int (main()::S::*)() const]'
test.cpp:14:31: required from here
FOO/include/range-v3/std/detail/associated_types.hpp:73:15: error: no class template named 'apply' in 'struct ranges::detail::enable_if<false>'
73 | using enable_if_t = typename enable_if<B>::template apply<T>;
| ^~~~~~~~~~~
shell returned 1
Making the projection a lambda...
ranges::find( ss, 1, [](auto const& s){ return s.get_i(); } );
...works but seems wasted typing.
Referring directly to the data member...
ranges::find(ss, 1, &S::i);
...works but is not possible if it should be encapsulated behind a const getter, transformer, etc.
What am I doing wrong? Can I not use a pointer-to-member-function as projection? Is it intended?
Edit: clang++ (also on MSYS2) does work here. So I guess this must be a bug in g++. Off to Bugzilla I go... edit: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94973
This is caused by GCC on Windows defaulting to -fms-extensions for compatibility with Microsoft compilers, and that pulling in a non-standard extension that introduces ambiguity between pointers-to-member-data vs -functions written as instance.*member.
We can pass -fno-ms-extensions to stop this and compile such code succesfully, until GCC remove that particular extension, which seems unnecessary and unhelpful nowadays.
Jonathan answered this on my GCC bug 94973:
Jonathan Wakely 2020-05-06 16:26:58 UTC
Aha, the same problem happens on linux if I compile with -fms-extensions
This is the old MS extension that causes x.*f to be accepted when f is a pointer to member function, which should only be valid when used as (x.*f)().
That causes ranges::invoke to think that the projection is a pointer to data member, when actually it's a pointer to member function.
See also PR 94771 comment 4.
Jason, do we want to disable that extension in SFINAE contexts?
Jonathan Wakely 2020-05-06 16:47:42 UTC
They're on by default for mingw, for compatibility with the MS compiler (but in this case it seems the relevant extension is ancient history).
After upgrade boost version 1.72.0, the following program which uses boost::asio cannot be compiled.I noticed that the read_until signature has changed since version 1.70.0.
Example in Coliru
#include <iostream>
#include <boost/asio.hpp>
class framed_streambuf: public boost::asio::streambuf
{
};
int main()
{
std::cout << "Using Boost "
<< BOOST_VERSION / 100000 << "." // major version
<< BOOST_VERSION / 100 % 1000 << "." // minor version
<< BOOST_VERSION % 100 // patch level
<< std::endl;
using boost::asio::ip::tcp;
framed_streambuf streambuf;
boost::asio::io_service io_service{1};
tcp::socket client_socket(io_service);
auto bytes_transferred = read_until(client_socket, streambuf, '#');
return 0;
}
Compilation errors:
/usr/local/include/boost/asio/impl/read_until.hpp: In instantiation of 'std::size_t boost::asio::read_until(SyncReadStream&, DynamicBuffer_v1&&, char, boost::system::error_code&, typename std::enable_if<(boost::asio::is_dynamic_buffer_v1<typename std::decay<_Func>::type>::value && (! boost::asio::is_dynamic_buffer_v2<typename std::decay<_Func>::type>::value))>::type*) [with SyncReadStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp>; DynamicBuffer_v1 = framed_streambuf&; std::size_t = long unsigned int; typename std::enable_if<(boost::asio::is_dynamic_buffer_v1<typename std::decay<_Func>::type>::value && (! boost::asio::is_dynamic_buffer_v2<typename std::decay<_Func>::type>::value))>::type = void]':
/usr/local/include/boost/asio/impl/read_until.hpp:86:45: required from 'std::size_t boost::asio::read_until(SyncReadStream&, DynamicBuffer_v1&&, char, typename std::enable_if<(boost::asio::is_dynamic_buffer_v1<typename std::decay<_Func>::type>::value && (! boost::asio::is_dynamic_buffer_v2<typename std::decay<_Func>::type>::value))>::type*) [with SyncReadStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp>; DynamicBuffer_v1 = framed_streambuf&; std::size_t = long unsigned int; typename std::enable_if<(boost::asio::is_dynamic_buffer_v1<typename std::decay<_Func>::type>::value && (! boost::asio::is_dynamic_buffer_v2<typename std::decay<_Func>::type>::value))>::type = void]'
main.cpp:20:70: required from here
/usr/local/include/boost/asio/impl/read_until.hpp:101:42: error: use of deleted function 'framed_streambuf::framed_streambuf(const framed_streambuf&)'
101 | typename decay<DynamicBuffer_v1>::type b(
| ^
main.cpp:4:7: note: 'framed_streambuf::framed_streambuf(const framed_streambuf&)' is implicitly deleted because the default definition would be ill-formed:
4 | class framed_streambuf: public boost::asio::streambuf
| ^~~~~~~~~~~~~~~~
main.cpp:4:7: error: use of deleted function 'boost::asio::basic_streambuf<>::basic_streambuf(const boost::asio::basic_streambuf<>&)'
In file included from /usr/local/include/boost/asio.hpp:36,
from main.cpp:2:
/usr/local/include/boost/asio/basic_streambuf.hpp:111:7: note: 'boost::asio::basic_streambuf<>::basic_streambuf(const boost::asio::basic_streambuf<>&)' is implicitly deleted because the default definition would be ill-formed:
111 | class basic_streambuf
| ^~~~~~~~~~~~~~~
/usr/local/include/boost/asio/basic_streambuf.hpp:111:7: error: 'boost::asio::detail::noncopyable::noncopyable(const boost::asio::detail::noncopyable&)' is private within this context
In file included from /usr/local/include/boost/asio/detail/std_fenced_block.hpp:23,
from /usr/local/include/boost/asio/detail/fenced_block.hpp:24,
from /usr/local/include/boost/asio/detail/executor_op.hpp:19,
from /usr/local/include/boost/asio/impl/system_executor.hpp:18,
from /usr/local/include/boost/asio/system_executor.hpp:129,
from /usr/local/include/boost/asio/associated_executor.hpp:21,
from /usr/local/include/boost/asio.hpp:21,
from main.cpp:2:
/usr/local/include/boost/asio/detail/noncopyable.hpp:32:3: note: declared private here
32 | noncopyable(const noncopyable&);
| ^~~~~~~~~~~
In file included from /usr/local/include/boost/asio/read_until.hpp:2795,
from /usr/local/include/boost/asio.hpp:114,
from main.cpp:2:
/usr/local/include/boost/asio/impl/read_until.hpp:108:59: error: 'framed_streambuf&' is not a class, struct, or union type
108 | typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
| ^~~~~~~~~~~~
/usr/local/include/boost/asio/impl/read_until.hpp:109:44: error: 'framed_streambuf&' is not a class, struct, or union type
109 | typedef buffers_iterator<buffers_type> iterator;
Since boost 1.70.0, the signature of read_until has changed:
template <typename SyncReadStream, typename DynamicBuffer_v1>
std::size_t read_until(SyncReadStream& s,
BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
char delim, boost::system::error_code& ec,
typename enable_if<
is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
&& !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
>::type*)
I know very little about enable_if, does it matter here?
How can we make a template accept only basic data types.
template <typename T>
void GetMaxValue( T& x )
{
//... Finds max Value
}
In the above function GetMaxValue we are able to pass any value without any an error.
But the std Function std::numeric_limits<T>::max() has handled it.
For example:
auto max = std::numeric_limits< std::map<int,int> >::max();
will Give an error error C2440: '<function-style-cast>' : cannot convert from 'int' to 'std::map<_Kty,_Ty>'
With constraints in C++20:
#include <type_traits>
template <class T>
requires std::is_arithmetic_v<T>
void GetMaxValue( T& x )
{
//... Finds max Value
}
Usage:
int a = 0;
GetMaxValue(a); // fine
std::vector<int> b;
GetMaxValue(b); // compiler error
Demo
With std::enable_if otherwise:
template <class T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
void GetMaxValue( T& x )
{
//... Finds max Value
}
Demo 2
The error messages pre-constraints are harder to read:
error: no matching function for call to 'GetMaxValue(std::vector<int>&)'
| GetMaxValue(b); // compiler error
| ^
Note: candidate: 'template<class T, typename std::enable_if<is_arithmetic_v<T>, int>::type <anonymous> > void GetMaxValue(T&)'
| void GetMaxValue( T& x )
| ^~~~~~~~~~~
note: template argument deduction/substitution failed:
error: no type named 'type' in 'struct std::enable_if<false, int>'
| template <class T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
| ^
In instantiation of 'void GetMaxValue(T&) [with T = int; typename std::enable_if<is_arithmetic_v<T>, int>::type <anonymous> = 0]'
vs
error: cannot call function 'void GetMaxValue(T&) [with T = std::vector<int>]'
| GetMaxValue(b); // compiler error
| ^
note: constraints not satisfied
In function 'void GetMaxValue(T&) [with T = std::vector<int>]':
required by the constraints of 'template<class T> requires is_arithmetic_v<T> void GetMaxValue(T&)'
note: the expression 'is_arithmetic_v<T>' evaluated to 'false'
| requires std::is_arithmetic_v<T>
| ~~~~~^~~~~~~~~~~~~~~~~~