I'm trying to use adjacent_difference with two different iterator types. The functor I have created takes the type used by the InputIterator as parameters and returns the type used by the OutputIterator. I don't understand why the code I included doesn't compile:
In file included from /usr/include/c++/4.9/numeric:62:0,
from 4: /usr/include/c++/4.9/bits/stl_numeric.h: In instantiation of '_OutputIterator
std::adjacent_difference(_InputIterator, _InputIterator,
_OutputIterator, _BinaryOperation) [with _InputIterator = __gnu_cxx::__normal_iterator >; _OutputIterator = __gnu_cxx::__normal_iterator >; _BinaryOperation = {anonymous}::CheckOp]':
48:85: required from here
/usr/include/c++/4.9/bits/stl_numeric.h:374:17: error: cannot convert
'_ValueType {aka Test}' to 'float' in assignment
*__result = __value;
// Example program
#include <iostream>
#include <string>
#include <numeric>
#include <vector>
struct Test
{
float first;
float second;
};
namespace{
class CheckOp {
public:
float operator()(Test x, Test y) const
{
float a = x.first - y.first;
float b = x.second - y.second;
return a + b;
}
};
}
int main()
{
std::vector<Test> testVec;
Test test1;
test1.first = 5.5F;
test1.second = 6.5F;
testVec.push_back(test1);
Test test2;
test2.first = 2.5F;
test2.second = 8.5F;
testVec.push_back(test2);
Test test3;
test3.first = 9.4F;
test3.second = 7.8F;
testVec.push_back(test3);
CheckOp checkOP;
std::vector<float> resultVec(testVec.size());
std::adjacent_difference(testVec.begin(), testVec.end(), resultVec.begin(), checkOP);
}
Note the description of adjacent_difference (from cppreference):
First, creates an accumulator acc whose type is InputIt's value type, initializes it with *first, and assigns the result to *d_first.
This implies that the input and output sequences must have the same, or at least a compatible, type.
Related
Consider the following example
#include <iostream>
#include <any>
#include <vector>
#include <map>
#include <typeinfo>
typedef enum TYPE{
INT8=0,
INT16=1,
INT32=2
} TYPE;
int main()
{
std::map<TYPE, std::any> myMap;
myMap[TYPE::INT8] = (int8_t)0;
myMap[TYPE::INT16] = (int16_t)0;
myMap[TYPE::INT32] = (int32_t)0;
std::vector<decltype(myMap[TYPE::INT8])> vec;
}
I have a map in this example, going from some enum to std::any. I actually need a flexible data structure that can map from a specific type (enum TYPE in this case), to multiple data types (different types of int), hence the use of std::any.
Going ahead, I would like to ascertain the type of value given for the key and construct a vector with it. I tried the above code, and it runs into a compilation error because decltype will return std::any(correctly so).
I would want to extract the "true type" from the std::any and create that type of vector. How would I achieve that.
A small snippet of the compilation error is as follows -
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:63:26: error: forming pointer to reference type 'std::any&'
63 | typedef _Tp* pointer;
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:112:7: error: forming pointer to reference type 'std::any&'
112 | allocate(size_type __n, const void* = static_cast<const void*>(0))
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1293:7: error: 'void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = std::any&; _Alloc = std::allocator<std::any&>; value_type = std::any&]' cannot be overloaded with 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::any&; _Alloc = std::allocator<std::any&>; value_type = std::any&]'
1293 | push_back(value_type&& __x)
TIA
As suggested in the comments by #Ted Lyngmo, I think std::variant serves you better. Especially with C++-20's templated lambdas, the std::visit function can work wonders with these to get around the awkwardness of dealing with type enums and the like.
Note that you can not get around the runtime type detection. In any case, here is an example of how it can work.
#include <cstdint>
#include <iostream>
#include <variant>
#include <vector>
using VariantScalar = std::variant<
std::int8_t, std::int16_t, std::int32_t>;
using VariantVector = std::variant<
std::vector<std::int8_t>,
std::vector<std::int16_t>,
std::vector<std::int32_t>>;
VariantVector fill_vector(VariantScalar scalar, std::size_t n)
{
auto make_vector = [n]<class IntType>(IntType v) -> VariantVector {
return std::vector<IntType>(n, v);
};
return std::visit(make_vector, scalar);
}
void print_vector(const VariantVector& vec)
{
std::visit([]<class T>(const std::vector<T>& vec) {
for(const T& s: vec)
std::cout << s << ' ';
std::cout << '\n';
}, vec);
}
int main()
{
VariantScalar s(std::int8_t(1));
VariantVector vec = fill_vector(s, 5);
print_vector(vec);
}
Assuming you have the following enum definition:
enum class TYPE{
INT8=0,
INT16=1,
INT32=2
};
Then you can define a helper:
template <TYPE>
struct my_type {}; // Base case
template <>
struct my_type<TYPE::INT8> {
using type = int8_t;
};
template <>
struct my_type<TYPE::INT16> {
using type = int16_t;
};
template <>
struct my_type<TYPE::INT32> {
using type = int32_t;
};
template <TYPE t>
using my_type = typename my_type<t>::type;
That you can use for your vector
std::vector<my_type<TYPE::INT8>> vec;
Consider the following uncomplicated code:
#include <thread>
#include <utility>
#include <vector>
#include <atomic>
#include <queue>
#include <iostream>
#include <functional>
using namespace std;
template<class It, class Fun>
void parallel_for(size_t num_threads, It first, It end, const Fun& fun) {
std::queue<std::thread> ts;
for (It it = first; it != end; ++it) {
if (std::distance(first, it) % num_threads == 0) {
fun(*it);
} else {
if (ts.size() == num_threads-1) {
ts.front().join();
ts.pop();
}
ts.push(std::thread(fun, std::ref(*it)));
}
}
while (not ts.empty()) {
ts.front().join();
ts.pop();
}
}
int main() {
std::atomic_int counter = 1;
auto lam = [&counter](auto& vl) {
vl = std::pair(counter++, -1);
};
// The following usage of std::ref works okay:
pair<int, int> x;
auto blam = bind(lam, ref(x));
blam();
// Nevertheless, the next line fails:
// lam(ref(x));
// As well as the next two ones:
// vector<pair<int, int>> v = {{4, 2}};
// parallel_for(thread::hardware_concurrency(), begin(v), end(v), lam);
return 0;
}
GCC's error on the last two lines, in particular, is
In file included from ./src/csc_cpp/passing_lambdas.cpp:1:
/usr/include/c++/10/thread: In instantiation of ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = const main()::<lambda(auto:1&)>&; _Args = {std::reference_wrapper<std::pair<int, int> >}; <template-parameter-1-3> = void]’:
./src/csc_cpp/passing_lambdas.cpp:22:26: required from ‘void parallel_for(size_t, It, It, const Fun&) [with It = __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int> > >; Fun = main()::<lambda(auto:1&)>; size_t = long unsigned int]’
./src/csc_cpp/passing_lambdas.cpp:47:71: required from here
/usr/include/c++/10/thread:136:44: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues
136 | typename decay<_Args>::type...>::value,
| ^~~~~
I am sure this is a trivial matter, but I am anyway struggling to understand this. I think I have been following the available examples on std::thread::thread()'s intended use quite closely, but this does not compile. What am I doing wrong?
First, let me clarify, because I'm not sure if it's obvious: the trick behind std::ref is that it returns an object of type std::reference_wrapper<T>, so you can use the result as object, but the object is implicitly convertible to T&, so it can be substituted where T& is needed.
lam(ref(x)); fails because you use auto in lam. Compiler doesn't know that you want vl to be std::pair<int, int>&, it deduces from what it gets. std::ref returns a temporary of std::reference_wrapper<std::pair<int, int>>, which cannot be bound to non-const reference. Use explicit type in lambda and it compiles:
auto lam = [&counter](std::pair<int, int>& vl) {
vl = std::pair(counter++, -1);
};
lam(std::ref(x));
Alternatively, you can explicitly convert to std::pair<int, int>& using get() or static_cast
auto lam = [&counter](auto& vl) {
vl = std::pair(counter++, -1);
};
lam(std::ref(x).get());
lam(static_cast<std::pair<int, int>&>(std::ref(x)));
The second part with parallel_for has exactly the same issue, you pass rvalue of std::reference_wrapper to lam.
About
lam(ref(x));
x is an lvalue while the ref(x) is a temporary reference_wrapper. You can not grab a temporary with an lvalue reference in your lam through auto&.
for that line, you can simply use
lam(x);
I'm using a template function, which the goal is reciever a vector and a function, and return the function type.
template <typename T, typename Function>
auto apply(const std::vector<T>& V, const Function &F){
vector<Function> x; # ERROR HERE
return x;
}
But the IDE give me error (http://coliru.stacked-crooked.com/a/ee6ce2127e013a18):
/usr/local/include/c++/10.2.0/ext/new_allocator.h: In instantiation of 'class __gnu_cxx::new_allocator<double(double)>':
/usr/local/include/c++/10.2.0/bits/allocator.h:116:11: required from 'class std::allocator<double(double)>'
/usr/local/include/c++/10.2.0/bits/stl_vector.h:87:21: required from 'struct std::_Vector_base<double(double), std::allocator<double(double)> >'
/usr/local/include/c++/10.2.0/bits/stl_vector.h:389:11: required from 'class std::vector<double(double), std::allocator<double(double)> >'
main.cpp:10:22: required from 'auto apply(const std::vector<T>&, const Function&) [with T = int; Function = double(double)]'
main.cpp:19:39: required from here
/usr/local/include/c++/10.2.0/ext/new_allocator.h:96:7: error: 'const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = double(double); __gnu_cxx::new_allocator<_Tp>::const_pointer = double (*)(double); __gnu_cxx::new_allocator<_Tp>::const_reference = double (&)(double)]' cannot be overloaded with '_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = double(double); __gnu_cxx::new_allocator<_Tp>::pointer = double (*)(double); __gnu_cxx::new_allocator<_Tp>::reference = double (&)(double)]'
96 | address(const_reference __x) const _GLIBCXX_NOEXCEPT
| ^~~~~~~
/usr/local/include/c++/10.2.0/ext/new_allocator.h:92:7: note: previous declaration '_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = double(double); __gnu_cxx::new_allocator<_Tp>::pointer = double (*)(double); __gnu_cxx::new_allocator<_Tp>::reference = double (&)(double)]'
92 | address(reference __x) const _GLIBCXX_NOEXCEPT
| ^~~~~~~
main.cpp: In function 'int main(int, char**)':
main.cpp:19:31: error: conversion from 'vector<double(double),allocator<double(double)>>' to non-scalar type 'vector<double,allocator<double>>' requested
19 | vector<double> r = ::apply(v, seno);
| ~~~~~~~^~~~~~~~~
This is call of the main function.
double seno( double n ) { return sin(n); }
int main( int argc, char* argv[]) {
vector<int> v{ 1, 2, 3, 4, 5 };
vector<double> r = ::apply(v, seno);
cout << r;
return 0;
}
I don't know what I'm doing wrong, so How can I improve this method and pass trough this error?
EDIT: The purpse to generalize the in method insted of using double in the vector is because I want o re-use in another way. So I've generalize the most that I can.
vector<Function> x; // ERROR HERE defines a vector of function pointers. But that's not what you want - you want a vector of the return type of the function. And that's what decltype() is for.
In your apply function, F is the function to be called and T is the type of the values in the vector being passed in. That means T() is the default value of the items in the vector (in this case the default value of int is 0). Then, F(T()) would actually call the function with 0 and return something so decltype(F(T())) tells you the type of the thing returned.
That means you need to write vector<decltype(F(T()))> x; instead.
T() works because the type is int and it is default constructible. As #alterigel said in the comments std::declval<T>() is better when the type is not default constructible.
So vector<decltype(F(std::declval<T>()))> x; might be needed in some situations.
The whole program would look like:
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
template <typename T, typename Function>
auto apply(const std::vector<T>& V, const Function &F) {
vector<decltype(F(T()))> x;
for(auto a : V)
x.push_back(F(a));
return x;
}
double seno( double n ) { return sin(n); }
int main( int argc, char* argv[]) {
vector<int> v{ 1, 2, 3, 4, 5 };
vector<double> r = ::apply(v, seno);
for (auto a : r)
cout << a << " ";
return 0;
}
Try it here: https://onlinegdb.com/SknTsVaHO
I am using the following template function in order to copy the first n elements from one vector to another.
// Example program
#include <iostream>
#include <string>
#include <vector>
template <typename Range>
inline std::vector<typename Range::value_type> take(const Range &iRange, int nbrElements) {
std::vector<typename Range::value_type> result;
if (nbrElements > iRange.size()) {
nbrElements = iRange.size();
}
std::copy_n(iRange, nbrElements, std::back_inserter(result));
return result;
}
int main()
{
std::vector<int> source = { 1, 2, 3, 4, 5, 6, 7,};
std::vector<int> destination = take(source, 7);
return 0;
}
The problem is that I am getting the following error and I don't understand why:
In instantiation of 'std::vector<typename Range::value_type>
take(const Range&, int) [with Range = std::vector<int>; typename
Range::value_type = int]':
22:48: required from here
10:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
In file included from /usr/include/c++/4.9/algorithm:62:0,
from 5:
/usr/include/c++/4.9/bits/stl_algo.h: In instantiation of '_OIter std::copy_n(_IIter, _Size, _OIter) [with _IIter = std::vector<int>;
_Size = int; _OIter = std::back_insert_iterator<std::vector<int> >]':
14:62: required from 'std::vector<typename Range::value_type> take(const Range&, int) [with Range = std::vector<int>; typename
Range::value_type = int]'
22:48: required from here
/usr/include/c++/4.9/bits/stl_algo.h:804:39: error: no matching function for call to '__iterator_category(std::vector<int>&)'
std::__iterator_category(__first));
^
/usr/include/c++/4.9/bits/stl_algo.h:804:39: note: candidate is:
In file included from /usr/include/c++/4.9/bits/stl_algobase.h:65:0,
from /usr/include/c++/4.9/bits/char_traits.h:39,
from /usr/include/c++/4.9/ios:40,
from /usr/include/c++/4.9/ostream:38,
from /usr/include/c++/4.9/iostream:39,
from 2:
/usr/include/c++/4.9/bits/stl_iterator_base_types.h:201:5: note: template<class _Iter> typename
std::iterator_traits<_Iterator>::iterator_category
std::__iterator_category(const _Iter&)
__iterator_category(const _Iter&)
^
/usr/include/c++/4.9/bits/stl_iterator_base_types.h:201:5: note: template argument deduction/substitution failed:
/usr/include/c++/4.9/bits/stl_iterator_base_types.h: In substitution of 'template<class _Iter> typename
std::iterator_traits<_Iterator>::iterator_category
std::__iterator_category(const _Iter&) [with _Iter =
std::vector<int>]':
/usr/include/c++/4.9/bits/stl_algo.h:804:39: required from '_OIter std::copy_n(_IIter, _Size, _OIter) [with _IIter =
std::vector<int>; _Size = int; _OIter =
std::back_insert_iterator<std::vector<int> >]'
14:62: required from 'std::vector<typename Range::value_type> take(const Range&, int) [with Range = std::vector<int>; typename
Range::value_type = int]'
22:48: required from here
/usr/include/c++/4.9/bits/stl_iterator_base_types.h:201:5: error: no type named 'iterator_category' in 'struct
std::iterator_traits<std::vector<int> >'
There are two issues with the code. The first is that it needs to have #include <algorithm>, which defines std::copy_n, and the second is that you need to take the begin() of range.
When fixed, this is what the code looks like:
// Example program
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
template <typename Range>
inline std::vector<typename Range::value_type> take(const Range &iRange, int nbrElements) {
std::vector<typename Range::value_type> result;
if (nbrElements > iRange.size()) {
nbrElements = iRange.size();
}
std::copy_n(iRange.begin(), nbrElements, std::back_inserter(result));
return result;
}
int main()
{
std::vector<int> source = { 1, 2, 3, 4, 5, 6, 7,};
std::vector<int> destination = take(source, 7);
return 0;
}
Shorter version
We can take advantage of std::vector's range constructor to write a shorter, very efficient version of take by using std::vector's range constructor:
template <class Range, class value_t = typename Range::value_type>
std::vector<value_t> take(const Range &range, size_t count) {
// Ensure count is at most range.size()
count = std::min(count, range.size());
return std::vector<value_t>(range.begin(), range.begin() + count);
}
You are almost there, only the first std::copy_n algorithm is wrong. Change the invocation to
using std::begin;
std::copy_n(begin(iRange), nbrElements, std::back_inserter(result));
and it should work as expected. Also, #include <algorithm> is missing, and you could prevent unnecessary allocations as you know the size of the resulting sequence:
result.reserve(nbrElements); // before the call to copy_n
You could try something like that:
template <typename type>
static std::vector<type> take(const std::vector<type> &iRange, size_t nbrElements)
{
if (nbrElements > iRange.size())
{
nbrElements = iRange.size();
}
std::vector<type> result;
result.insert(result.end(), iRange.begin(), iRange.begin() + nbrElements);
return result;
}
Edit:
You can also return vector directly:
return std::vector<type>(iRange.begin(), iRange.begin() + nbrElements);
Consider the following code:
#include <unordered_map>
#include <tuple>
namespace Test
{
template<typename State>
struct StateTableEntry
{
State state;
};
template<typename State>
using StateRow = std::unordered_map<int,StateTableEntry<State>>;
template<typename StateRowValueType>
auto& entryBAD(StateRowValueType& row)
{ return row.second; }
template<typename StateRowValueType>
auto entryOK(StateRowValueType& row) -> decltype((row.second))
{ return row.second; }
}
template<class T,int I,class O> std::enable_if_t<I==std::tuple_size<T>::value>
for_each_index_of(O&){}
template<class Tuple, int startingIndex=0, class Operation>
std::enable_if_t<startingIndex<std::tuple_size<Tuple>::value>
for_each_index_of(const Operation& operation)
{
operation(std::integral_constant<std::size_t,startingIndex>());
for_each_index_of<Tuple,startingIndex+1>(operation);
}
int main()
{
for_each_index_of<std::tuple<int>>([](const auto&)
{
Test::StateRow<long> stateRow;
for(auto& rowElement : stateRow)
{
auto& state(entryBAD(rowElement).state);
state=1;
}
});
}
If I try to compile it as is, gcc tells me
test.cpp: In instantiation of ‘main()::<lambda(const auto:1&)> [with auto:1 = std::integral_constant<long unsigned int, 0ul>]’:
test.cpp:29:14: required from ‘std::enable_if_t<(startingIndex < std::tuple_size<_Tp>::value)> for_each_index_of(const Operation&) [with Tuple = std::tuple<int>; int startingIndex = 0; Operation = main()::<lambda(const auto:1&)>; std::enable_if_t<(startingIndex < std::tuple_size<_Tp>::value)> = void]’
test.cpp:43:6: required from here
test.cpp:40:44: error: use of ‘template<class StateRowValueType> auto& Test::entryBAD(StateRowValueType&)’ before deduction of ‘auto’
auto& state(entryBAD(rowElement).state);
^
test.cpp:40:44: error: use of ‘auto& Test::entryBAD(StateRowValueType&) [with StateRowValueType = std::pair<const int, Test::StateTableEntry<long int> >]’ before deduction of ‘auto’
test.cpp:24:1: error: ‘std::enable_if_t<(I == std::tuple_size<_Tp>::value)> for_each_index_of(O&) [with T = std::tuple<int>; int I = 1; O = const main()::<lambda(const auto:1&)>; std::enable_if_t<(I == std::tuple_size<_Tp>::value)> = void]’, declared using local type ‘const main()::<lambda(const auto:1&)>’, is used but never defined [-fpermissive]
for_each_index_of(O&){}
^
But if I move the conde of lambda out of the lambda or replace call of entryBAD with entryOK, for some reason compilation succeeds. Same success if I move definition of entryBAD out of namespace Test.
Also, clang++ 3.6 compiles in all cases without complaints.
Is gcc right or is it a bug in it? If gcc is right, then what's wrong with the code?