I am having trouble aliasing the function boost::make_iterator_range
(I would like to hide boost behind an alias in case this particular library gets adopted into the standard sometime in the future.)
Is there any way this can be made to work?
#include <boost/range/iterator_range.hpp>
void Foo()
{
}
template< typename T >
void Bar()
{ }
template< typename T >
void Bar(char c)
{ }
void (&FooAlias)() = Foo; // ok
void (&BarAlias)() = Bar<int>; // ok
// boost::iterator_range<const size_t*> (&MakeIterRangeAlias)(const size_t*,const size_t*) =
// boost::make_iterator_range<const size_t*>; // not ok
int main(int argc, char** argv)
{
const size_t v[] = { 3, 5, 1, 5, 29, 15 };
boost::iterator_range<const size_t*> r
= boost::make_iterator_range( std::begin( v ), std::end( v )); // want to alias this
return 0;
}
The error message is:
In file included from /usr/include/boost/iterator/iterator_categories.hpp:15:0,
from /usr/include/boost/iterator/detail/facade_iterator_category.hpp:7,
from /usr/include/boost/iterator/iterator_facade.hpp:14,
from /usr/include/boost/range/iterator_range_core.hpp:23,
from /usr/include/boost/range/iterator_range.hpp:13,
from sandbox.cpp:2:
/usr/include/boost/mpl/eval_if.hpp: In instantiation of ‘boost::mpl::eval_if_c<true, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int* const> >’:
/usr/include/boost/range/iterator.hpp:63:63: instantiated from ‘boost::range_iterator<const long unsigned int* const>’
sandbox.cpp:20:10: instantiated from here
/usr/include/boost/mpl/eval_if.hpp:60:31: error: no type named ‘type’ in ‘boost::mpl::eval_if_c<true, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int* const> >::f_ {aka struct boost::range_const_iterator<const long unsigned int*>}’
/usr/include/boost/mpl/eval_if.hpp: In instantiation of ‘boost::mpl::eval_if_c<false, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int*> >’:
/usr/include/boost/range/iterator.hpp:63:63: instantiated from ‘boost::range_iterator<const long unsigned int*>’
sandbox.cpp:20:10: instantiated from here
/usr/include/boost/mpl/eval_if.hpp:60:31: error: no type named ‘type’ in ‘boost::mpl::eval_if_c<false, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int*> >::f_ {aka struct boost::range_mutable_iterator<const long unsigned int*>}’
sandbox.cpp:20:10: error: invalid initialization of non-const reference of type ‘void (&)(const size_t*, const size_t*) {aka void (&)(const long unsigned int*, const long unsigned int*)}’ from an rvalue of type ‘<unresolved overloaded function type>’
make: *** [sandbox] Error 1
Using function pointers is a suboptimal way alias a function. It is not as flexible as the original (it can no longer be a template) and you now need to know the exact signature of the function, which may or may not be stable.
Instead try this approach.
template< typename ... Args >
auto MakeIterRangeAlias( Args&& ... args ) -> decltype( /* copy return line here */ )
{
return boost::make_iterator_range( std::forward<Args>(args)... );
}
With almost no work on your part the alias supports the exact signature of the original. Even if it dramatically changes, you're still set. Further, unlike the function pointer approach the optimizer will be able to trivially inline MakeIterRangeAlias so that there is no runtime overhead.
Related
I have a class with a constructor but the compilation fails with the error:
error: use of deleted function 'std::atomic<long unsigned int>::atomic(const std::atomic<long unsigned int>&)'
I'm struggling to understand what this error means. I've been trying to update some code from using tbb::atomic to using std::atomic, and this error wasn't appearing before with tbb::atomic.
The bit of code that upsets the compiler is:
#include <boost/aligned_storage.hpp>
template <typename T>
class Holder<T,true>
{
public:
//! Construct a value (there mustn't be one already)
template <typename ARG>
void Construct(const ARG &arg) { new(Raw()) T(arg); }
private:
typename boost::aligned_storage<sizeof(T), boost::alignment_of<T>::value>::type impl;
void *Raw() { return &impl; }
};
Specifically the line:
void Construct(const ARG &arg) { new(Raw()) T(arg); }
I'd be very grateful if anyone could help me understand what is going on.
EDIT:
Full error message:
holder.hpp:75:34: error: use of deleted function 'std::atomic<long unsigned int>::atomic(const std::atomic<long unsigned int>&)'
75 | void Construct(const T &arg) { new(Raw()) T(arg); }
| ^~~~~~~~~~~~~~~~~
In file included from /include/TPtools/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp:19,
from /include/TPtools/boost/smart_ptr/detail/sp_counted_base.hpp:48,
from /include/TPtools/boost/smart_ptr/detail/shared_count.hpp:29,
from /include/TPtools/boost/smart_ptr/shared_ptr.hpp:28,
from /include/TPtools/boost/shared_ptr.hpp:17,
from movegate.cpp:14:
/pkgsData/gcc-v9.3.0p1/Linux/RHEL6.0-2013-x86_64/include/c++/9.3.0/atomic:824:7: note: declared here
824 | atomic(const atomic&) = delete;
| ^~~~~~
holder.hpp: In instantiation of 'void Holder<T, true>::Construct(const T&) [with T = std::atomic<long unsigned int>; T = std::atomic<long unsigned int>]':
element.hpp:185:9: required from 'void Element<PRESENT, ABSENT>::Accessor<PRESENCE>::MakePresentImpl(const ARG&) const [with ARG = std::atomic<long unsigned int>; PRESENCE = Cluster<Element<std::atomic<long unsigned int>, Link>, true>::NonLockingPresence; PRESENT = std::atomic<long unsigned int>; ABSENT = Link]'
element.hpp:119:7: required from 'Element<PRESENT, ABSENT>::PresentResult Element<PRESENT, ABSENT>::Accessor<PRESENCE>::MakePresent(const ARG&) const [with ARG = std::atomic<long unsigned int>; PRESENCE = Cluster<Element<std::atomic<long unsigned int>, Link>, true>::NonLockingPresence; PRESENT = std::atomic<long unsigned int>; ABSENT = Link; Element<PRESENT, ABSENT>::PresentResult = std::atomic<long unsigned int>&]'
dispenser.hpp:78:5: required from 'Index Dispenser<T>::Insert(const T&) [with T = std::atomic<long unsigned int>]'
I am new to c++, I want to create different type of object by parameter, like this:
if (version_ == "v1") {
typename std::unordered_map<T, TIndex> uniq;
} else {
typename absl::flat_hash_map<T, TIndex> uniq;
}
uniq.reserve(2 * N);
However, this code compile failed:
error: 'uniq' was not declared in this scope
uniq.reserve(2 * N);
^
Then, I change the code:
std::unordered_map<T, TIndex> uniq1;
absl::flat_hash_map<T, TIndex> uniq2;
auto uniq = uniq1;
if (version_ == "v2") {
uniq = uniq2;
}
uniq.reserve(2 * N);
It also filed:
error: no match for 'operator=' (operand types are 'std::unordered_map<bool, long long int, std::hash<bool>, std::equal_to<bool>, std::allocator<std::pair<const bool, long long int> > >' and 'absl::flat_hash_map<bool, long long int, absl::hash_internal::Hash<bool>, std::equal_to<bool>, std::allocator<std::pair<const bool, long long int> > >')
uniq = uniq2;
^
How can I implement this feature in c++?
You can't determine a compile-time type at runtime.
What you can do is wrap all your work in templates, and then "kick off" with a specific type.
(That is, deploy the old "add a level of indirection" solution.)
Rough sketch:
template<typename Table>
void do_work(int N)
{
Table t;
t.reserve(2 * N);
....
}
//...
if (version == "v1")
{
do_work<std::unordered_map<T, TIndex>>(N);
}
else
{
do_work<absl::flat_hash_map<T, TIndex>>(N);
}
I am using the optional feature for the 1st time, any idea what is wrong in this code I wish to retrieve the value from the tuple which is stored in retCode
#include <iostream>
#include <experimental/optional>
std::experimental::optional<std::tuple<uint16_t, uint32_t, uint32_t>> addEntity();
std::experimental::optional<std::tuple<uint16_t, uint32_t, uint32_t>> addEntity() {
uint32_t ipR = 1111;
uint32_t ipU = 2222;
uint16_t entityId = 0;
return std::make_tuple(entityId, ipR, ipU);
}
int main()
{
auto retCode = addEntity();
std::cout<<std::get<0>(retCode)<<std::endl;
return 0;
}
Compilation Errors
g++ experiment.cpp
In file included from /usr/include/c++/7/bits/move.h:54:0,
from /usr/include/c++/7/bits/nested_exception.h:40,
from /usr/include/c++/7/exception:143,
from /usr/include/c++/7/ios:39,
from /usr/include/c++/7/ostream:38,
from /usr/include/c++/7/iostream:39,
from experiment.cpp:1:
/usr/include/c++/7/type_traits: In instantiation of ‘struct std::is_trivially_destructible<std::tuple<short unsigned int, unsigned int, unsigned int> >’:
/usr/include/c++/7/experimental/optional:203:5: required from ‘class std::experimental::fundamentals_v1::optional<std::tuple<short unsigned int, unsigned int, unsigned int> >’
There's no implicit conversion from optional<T> to T, you need to extract the value.
int main()
{
auto retCode = addEntity();
std::cout<<std::get<0>(retCode.value())<<std::endl; // can throw std::bad_optional_access
return 0;
}
Unless you have other places which require addEntity to return an optional tuple, not just places where you call addEntity to initialise an optional tuple, it should just return a tuple.
I have a Register function which takes a std::function<void(const uint8_t* data, size_t len)> as a parameter. I want to use the member function of an object as the target.
I found this question according to which the answer is to use std::bind to bind the first first argument (the implicit this pointer) to the actual object pointer and then use it as the std::function argument.
This however doesn't work anymore in neither C++11, C++14 nor C++17?
Consider the following test program.
#include <iostream>
#include <cstdint>
#include <functional>
void Register(std::function<void(const uint8_t* data, size_t len)> func) {
//Dummy - directly call into function
func(nullptr, 0);
}
class TestClass {
public:
void TestRegister() {
Register(
std::bind(&TestClass::TestTarget, this, std::placeholders::_1)
);
}
void TestTarget(const uint8_t* data, size_t len) {
(void) data;
(void) len;
std::cout << "Hello there" << std::endl;
}
};
int main() {
TestClass testObj;
testObj.TestRegister();
return 0;
}
When compiling for -std=c++17 this throws a rather cryptic error message (I have no idea what it's trying to say here with Wrong number of arguments for pointer-to-member):
In file included from /home/max/Documents/TestingFunctions/main.cpp:3:0:
/usr/include/c++/7/functional: In instantiation of ‘struct std::_Bind_check_arity<void (TestClass::*)(const unsigned char*, long unsigned int), TestClass*, const std::_Placeholder<1>&>’:
/usr/include/c++/7/functional:854:12: required from ‘struct std::_Bind_helper<false, void (TestClass::*)(const unsigned char*, long unsigned int), TestClass*, const std::_Placeholder<1>&>’
/usr/include/c++/7/functional:875:5: required by substitution of ‘template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void (TestClass::*)(const unsigned char*, long unsigned int); _BoundArgs = {TestClass*, const std::_Placeholder<1>&}]’
/home/max/Documents/TestingFunctions/main.cpp:14:78: required from here
/usr/include/c++/7/functional:841:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
static_assert(_Varargs::value
^~~~~~~~~~~~~
/home/max/Documents/TestingFunctions/main.cpp: In member function ‘void TestClass::TestRegister()’:
/home/max/Documents/TestingFunctions/main.cpp:14:26: error: could not convert ‘std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void (TestClass::*)(const unsigned char*, long unsigned int); _BoundArgs = {TestClass*, const std::_Placeholder<1>&}; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind<void (TestClass::*(TestClass*, std::_Placeholder<1>))(const unsigned char*, long unsigned int)>](((TestClass*)this), std::placeholders::_1)’ from ‘std::_Bind_helper<false, void (TestClass::*)(const unsigned char*, long unsigned int), TestClass*, const std::_Placeholder<1>&>::type {aka std::_Bind<void (TestClass::*(TestClass*, std::_Placeholder<1>))(const unsigned char*, long unsigned int)>}’ to ‘std::function<void(const unsigned char*, long unsigned int)>’
std::bind(&TestClass::TestTarget, this, std::placeholders::_1)
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Replacing the TestRegister function with one that does the exact same thing in a lambda expression compiles and runs without problems.
void TestRegister() {
Register(
[this](const uint8_t* data, size_t len) {
TestTarget(data, len);
}
);
}
Question: Why does the std::bind approach from the linked question not work? Was this feature removed or do I have an error in my code?
Your function Register expects a function with two parameters, but you try to pass to it a function with one placeholded parameter.
void TestRegister() {
Register(
std::bind(&TestClass::TestTarget, this, std::placeholders::_1, std::placeholders::_2)
);
}
Your function takes two parameters, while you are only passing one placeholder.
std::bind(&TestClass::TestTarget, this, std::placeholders::_1, std::placeholders::_2);
This code does not compile:
ErrorTolerantSearch e;
e.readStringsFromFile("test.txt");
e.buildQgramIndex(3);
vector<map<uint, uint>*> lists;
lists.push_back(&e._qgramIndex["ret"]); // ignore this, assume container not empty
lists.push_back(&e._qgramIndex["coo"]); // ignore this, assume container not empty
map<uint, uint> resunion = e.computeUnion(lists); // <-- this makes problems
This is a part of the header
class ErrorTolerantSearch {
public:
void readStringsFromFile(string fileName);
void buildQgramIndex(uint q);
map<uint, uint> computeUnion(const vector<const map<uint, uint>*> & lists);
map<string, map<uint, uint> > _qgramIndex;
};
This is the error the compiler gives:
ErrorTolerantSearchTest.cpp: In member function ‘virtual void ErrorTolerantSearchTest_computeUnion_Test::TestBody()’:
ErrorTolerantSearchTest.cpp:89:50: error: no matching function for call to ‘ErrorTolerantSearch::computeUnion(std::vector<std::map<unsigned int, unsigned int>*>&)’
ErrorTolerantSearchTest.cpp:89:50: note: candidate is:
In file included from ErrorTolerantSearchTest.cpp:36:0:
./ErrorTolerantSearch.h:56:19: note: std::map<unsigned int, unsigned int> ErrorTolerantSearch::computeUnion(const std::vector<const std::map<unsigned int, unsigned int>*>&)
./ErrorTolerantSearch.h:56:19: note: no known conversion for argument 1 from ‘std::vector<std::map<unsigned int, unsigned int>*>’ to ‘const std::vector<const std::map<unsigned int, unsigned int>*>&’
make[1]: *** [ErrorTolerantSearchTest] Fehler 1
But what is the problem? I dont get it. I never had problems with passing non-const variables to functions with const parameters by reference.
std::vector<const T> is not equal to std::vector<T> and no convertible to it.