I need to create a constexpr template function to sum container, and pass the static assert. This is my code, but I have to questions.
I recived this error: assignment of read-only reference ‘res’.
Is the sum function written correctly?
#include <iostream>
#include <array>
using namespace std;
template <typename T>
constexpr auto Sum(const T& arr)
{
using arrType = decltype(*arr.begin());
arrType res = 0;
for (auto it = arr.begin(); it != arr.end(); it++) {
res += *it;
}
return res;
}
int main()
{
constexpr array<int, 3> base{5, 2, 0};
static_assert(Sum(base) == 7);
return 0;
}
Your code doesn't compile because since arr is const reference, decltype(*arr.begin()) is const int. So your res is const and you can't assign to it in your loop.
To fix only that error, you should use std::decay, i.e:
using arrType = std::decay_t<decltype(*arr.begin())>;
You don't specify what you mean by "container". If you mean the standard library's definition (which is supported by all STL containers), you can use value_type instead and also further simplify your code:
template <typename T>
constexpr auto Sum(const T& arr) {
typename T::value_type result{};
for (auto const& x : arr) {
result += x;
}
return result;
}
If you have C++20, you can also use std::accumulate:
template <typename T>
constexpr auto Sum(const T& arr)
{
return std::accumulate(arr.begin(), arr.end(),
typename T::value_type{});
}
The problem lies with decltype(*arr.begin()), which gives const U& if U represents the type of the elements of the container arr.
Applying std::remove_reference and std::remove_cv makes it compile.
#include <iostream>
#include <type_traits>
#include <array>
using namespace std;
template <typename T>
constexpr auto Sum(const T& arr)
{
using arrType = remove_cv_t<remove_reference_t<decltype(*arr.begin())>>;
arrType res = 0;
for (auto it = arr.begin(); it != arr.end(); it++) {
res += *it;
}
return res;
}
int main()
{
constexpr array<int, 3> base{5, 2, 0};
static_assert(Sum(base) == 7);
return 0;
}
Related
Is there a way to "expand" a vector variable in an initialization list to achieve something to the effect of
std::vector<int> tmp1{1,1,2,3,5};
std::vector<int> tmp2{11,tmp1,99};
//tmp2 == {11,1,1,2,3,5,99}
I know it could be done with std::copy or insert. Was wondering if there was list-initialization way achieve that. something like [11,*tmp1,99] in python
With this solution you can have something close the the syntax you want.
(And yes some of the work will be done at runtime)
#include <type_traits>
#include <vector>
namespace details
{
// recursive part
template<typename type_t, typename arg_t, typename... args_t>
void append_to_vector(std::vector<type_t>& vec, arg_t value, args_t&&... values)
{
if constexpr (std::is_same_v<arg_t, std::vector<type_t>>)
{
vec.insert(vec.end(), value.begin(), value.end());
}
else
{
vec.push_back(value);
}
if constexpr (sizeof...(args_t) > 0)
{
append_to_vector(vec, std::forward<args_t>(values)...);
}
}
}
template<typename type_t, typename... args_t>
std::vector<type_t> make_vector(args_t&&... values)
{
std::vector<type_t> retval;
if constexpr (sizeof...(args_t) > 0)
{
details::append_to_vector(retval, std::forward<args_t>(values)...);
}
return retval;
};
int main()
{
auto tmp1 = make_vector<int>(1, 1, 2, 3, 5);
auto tmp2 = make_vector<int>(11, tmp1, 99);
return 0;
}
One option could be to create a make_vector variadic function template that checks if the current argument supports std::begin(). If it supports std::begin(), use the vector's insert member function, otherwise, use emplace_back. That should make it possible to make a vector from any container (with the correct T).
First, one type trait to check if the current argument supports std::begin() and one that checks if it supports std::size(). std::size() will be used to calculate how much space the final vector will need. Reserving space is often used to avoid reallocating space (and moving elements) when populating vectors when the final (or minimal) amount of elements is known - as it is in this case.
#include <iterator>
#include <type_traits>
template<typename T>
class has_begin {
template<typename TT>
static auto test(int) ->
decltype( std::begin(std::declval<const TT&>()), std::true_type() );
template<typename>
static auto test(...) -> std::false_type;
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template<class T>
inline constexpr bool has_begin_v = has_begin<T>::value;
template<typename T>
class has_size {
template<typename TT>
static auto test(int) ->
decltype( std::size(std::declval<const TT&>()), std::true_type() );
template<typename>
static auto test(...) -> std::false_type;
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template<class T>
inline constexpr bool has_size_v = has_size<T>::value;
Then, the actual make_vector function template and helpers to calculate the actual size and determine what to do with one specific argument.
#include <utility>
#include <vector>
namespace detail {
template<class T, class Arg>
size_t make_vector_capacity(Arg&& arg) {
if constexpr(std::is_same_v<T, std::remove_cv_t<std::remove_reference_t<Arg>>>) {
// same type as in the vector, return 1
return 1;
} else if constexpr(has_size_v<Arg>) {
// a container supporting std::size
return std::size(arg);
} else if constexpr(has_begin_v<Arg>) {
// a container but not supporting std::size
return std::distance(std::begin(arg), std::end(arg));
} else {
// fallback
return 1;
}
}
template<class T, class Arg>
void make_vector_helper(std::vector<T>& v, Arg&& arg) {
if constexpr(std::is_same_v<T, std::remove_cv_t<std::remove_reference_t<Arg>>>) {
// same type as in the vector, insert it as-is
v.emplace_back(std::forward<Arg>(arg));
} else if constexpr(has_begin_v<Arg>) {
// arg supports std::begin, use insert
v.insert(v.end(), std::begin(arg), std::end(arg));
} else {
// fallback
v.emplace_back(std::forward<Arg>(arg));
}
}
} // namespace detail
template<class T, class... Args>
std::vector<T> make_vector(Args&&... args) {
std::vector<T> rv;
// a fold expression to calculate the capacity needed:
rv.reserve( (detail::make_vector_capacity<T>(args) + ...) );
// a fold expression to call make_vector_helper for each argument
(detail::make_vector_helper(rv, std::forward<Args>(args)), ...);
return rv;
}
A usage example, mixing different containers and single values of std::string:
#include <initializer_list>
#include <iostream>
#include <list>
#include <vector>
#include <string>
int main() {
using namespace std::string_literals;
const std::string arr[] = {"3"s, "4"s};
const std::vector vec{"5"s, "6"s, "7"s , "8"s};
const std::list list{"9"s,"10"s};
auto init = {"13"s, "14"s, "15"s};
const auto tmp2 = make_vector<std::string>("1"s, "2"s, arr, vec, list,
"11"s, "12"s, init );
for(const auto& e: tmp2) std::cout << e <<' ';
}
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Demo
No, it is not possible but you can make a helper that allows can do it:
#include <array>
#include <type_traits>
// Containerize MaybeContainer type if it not equal to T.
template<typename T, typename MaybeContainer>
using impl_containerize = std::conditional_t<std::is_same_v<T,std::decay_t<MaybeContainer>>,std::array<T,1>,MaybeContainer>;
// Concatenate containers
template<typename Container,typename...Args>
Container impl_construct(Args&&...args){
Container c;
(c.insert(c.end(), std::begin(args), std::end(args)), ...);
return c;
}
template<typename Container,typename...Args>
Container construct(Args&&...args){
using T = typename Container::value_type;
return impl_construct<Container, impl_containerize<T,Args>...>({std::forward<Args>(args)}...);
}
#include <iostream>
#include <vector>
int main()
{
std::vector<int> tmp1{1,3,5,7,9};
const auto tmp2 = construct<std::vector<int>>(2,4,tmp1,6);
for(const auto& e: tmp2){
std::cout<<e<<' ';
}
}
Output
2 4 1 3 5 7 9 6
I have a collection of equally-sized vectors and want to provide an interface for the user to obtain an iterator range over a subset of these vectors.
The following example shows the problematic line inside getRange: its idea is to receive a bunch of types (specifying the types of vectors) and equally many indices (specifying the locations of the vectors). The code compiles, but the problem is that i++ never gets executed as intended, i.e., the call is always with just i (which equals 0). This will also lead to runtime errors via boost::get if the user tries to get distinct types.
This is probably a well-known issue. What's a neat solution to it?
#include <vector>
#include <boost/variant.hpp>
#include <boost/range/combine.hpp>
template <typename... T>
struct VectorHolder
{
template<typename X>
using Iterator = typename std::vector<X>::const_iterator;
std::vector<boost::variant<std::vector<T>...> > vecs_;
template <typename X>
auto begin(int idx) const {
return boost::get<std::vector<X> >(vecs_.at(idx)).cbegin();
}
template <typename X>
auto end(int idx) const {
return boost::get<std::vector<X> >(vecs_.at(idx)).cend();
}
};
template <typename... T, typename VectorHolder>
auto getRange(const VectorHolder& vh, const std::vector<int>& idx)
{
assert(sizeof...(T) == idx.size());
// Fetch a boost::iterator_range over the specified indices
std::size_t i = 0;
std::size_t j = 0;
// PROBLEM: i and j not incremented as intended
return boost::combine(
boost::iterator_range<VectorHolder::Iterator<T>>(
vh.begin<T>(idx[i++]), vh.end<T>(idx[j++]))...);
}
int main()
{
VectorHolder<bool, int, double> vh;
vh.vecs_.push_back(std::vector<int>(5, 5));
vh.vecs_.push_back(std::vector<bool>(5));
vh.vecs_.push_back(std::vector<double>(5, 2.2));
vh.vecs_.push_back(std::vector<int>(5, 1));
const std::vector<int> idx = { 0, 3 };
for (auto t : getRange<int, int>(vh, idx))
{
std::cout << t.get<0>() << " " << t.get<1>() << "\n";
}
}
std::index_sequence helps:
template <typename... Ts, typename VectorHolder, std::size_t ... Is>
auto getRange(const VectorHolder& vh, const std::vector<int>& idx, std::index_sequence<Is...>)
{
assert(sizeof...(Ts) == idx.size());
return boost::combine(
boost::iterator_range<typename VectorHolder::template Iterator<Ts>>(
vh.template begin<Ts>(idx[Is]), vh.template end<Ts>(idx[Is]))...);
}
template <typename... Ts, typename VectorHolder>
auto getRange(const VectorHolder& vh, const std::vector<int>& idx)
{
return getRange<Ts...>(vh, idx, std::index_sequence_for<Ts...>());
}
Demo
From http://en.cppreference.com/w/cpp/container/unordered_map/unordered_map, unordered_map can use lambda functions for hashing function. It is also answered in the following: How to use lambda function as hash function in unordered_map?
My question is about hashing a struct which includes a container, say a vector. Since cpprefence has the following code example of
#include <algorithm>
#include <cassert>
#include <string>
#include <unordered_set>
#include <vector>
#include <unordered_map>
using std::hash;
using std::string;
using std::unordered_set;
using std::vector;
int main(int argc, char* argv[]) {
struct Goo {int val; };
auto hash = [](const Goo &g){ return std::hash<int>{}(g.val); };
auto comp = [](const Goo &l, const Goo &r){ return l.val == r.val; };
std::unordered_map<Goo, double, decltype(hash), decltype(comp)> m8(10, hash, comp);
return 0;
}
I have modified it so that it tries to use vector<int> in the Goo.
#include <algorithm>
#include <cassert>
#include <string>
#include <unordered_set>
#include <vector>
#include <unordered_map>
using std::hash;
using std::string;
using std::unordered_set;
using std::vector;
int main() {
using vint = std::vector<int>;
struct Goo { vint v; };
auto hash = [](const Goo &g){
std::size_t hash_value = 0;
for (const int& i : g.v) {
hash_value ^= std::hash<int>{}(i);
}
return hash_value;
};
auto comp = [](const Goo &l, const Goo &r){
return unordered_set<int>(l.v.begin(), l.v.end()) ==
unordered_set<int>(r.v.begin(), r.v.end());
};
vint here;
std::unordered_map<Goo, double, decltype(hash), decltype(comp)>
m8(here,0, hash, comp);
return 0;
}
This code doesn't compile. The compiler complains about not no matching function for call to ‘std::unordered_map<main(int, char**)::Goo. The number of arguments seems to be not the issue, but something must be working not correctly. I would greatly appreciate your guidance.
I am using g++ -std=c++17 by the way.
I think that you didn't understand the example. This line:
std::unordered_map<Goo, double, decltype(hash), decltype(comp)> m8(10, hash, comp);
is responsible for creating unordered_map with at least 10 buckets and provided hash and comp functions. It does not create any unordered_map with 10 elements. Therefore, your code should look like this:
using vint = std::vector<int>;
struct Goo { vint v; };
auto hash = [](const Goo &g){
std::size_t hash_value = 0;
for (const int& i : g.v) {
hash_value ^= std::hash<int>{}(i);
}
return hash_value;
};
auto comp = [](const Goo &l, const Goo &r){
return std::unordered_set<int>(l.v.begin(), l.v.end()) ==
std::unordered_set<int>(r.v.begin(), r.v.end());
};
std::unordered_map<Goo, double, decltype(hash), decltype(comp)>
m8(10, hash, comp);
unordered_map simply does not have any constructor that will mach this:
std::unordered_map<Goo, double, decltype(hash), decltype(comp)>
m8(here, 0, hash, comp);
I suggest using the composable hashing infrastructure from N3980 Types Don't Know #. It also saves you from error-prone manual hash combining.
An example of hashing a structure with two members, one of which is a vector:
// Hashing infrastructure begin.
class fnv1a
{
std::size_t state_ = 14695981039346656037u;
public:
using result_type = std::size_t;
void operator()(void const* key, std::size_t len) noexcept {
unsigned char const* p = static_cast<unsigned char const*>(key);
unsigned char const* const e = p + len;
for (; p < e; ++p)
state_ = (state_ ^ *p) * 1099511628211u;
}
explicit operator result_type() noexcept {
return state_;
}
};
template<class HashAlgorithm>
struct uhash
{
using result_type = typename HashAlgorithm::result_type;
template <class T>
result_type operator()(T const& t) const noexcept {
HashAlgorithm h;
hash_append(h, t);
return static_cast<result_type>(h);
}
};
template<class HashAlgorithm, class T>
typename std::enable_if<std::is_integral<T>::value>::type
inline hash_append(HashAlgorithm& h, T const& t) noexcept {
h(&t, sizeof t);
}
template<class HashAlgorithm, class T, class... Args>
void hash_append(HashAlgorithm& h, std::vector<T, Args...> const& v) noexcept {
for(auto const& t : v)
hash_append(h, t);
hash_append(h, v.size());
}
template<class HashAlgorithm, class T, class... Args>
void hash_append(HashAlgorithm& h, std::unordered_map<T, Args...> const& v) noexcept {
for(auto const& t : v)
hash_append(h, t);
hash_append(h, v.size());
}
// Hashing infrastructure end
struct Goo
{
std::vector<int> a;
int b;
template<class HashAlgorithm>
friend void hash_append(HashAlgorithm& h, Goo const& v) noexcept {
hash_append(h, v.a);
hash_append(h, v.b);
}
bool operator==(Goo const& other) const {
return a == other.a && b == other.b;
}
};
int main() {
std::unordered_map<Goo, double, uhash<fnv1a>> m;
m[Goo{{1,2,3}, 1}] = 1;
}
I am trying to write a simple template function that prints every element of some container, without using for loops. So far, I have
#include <iostream>
#include <vector>
#include <algorithm>
template <typename T> void print_with_space(T x){
std::cout << x << ' ';
}
template <typename T> void print_all(T beg, T end){
std::for_each(beg, end, print_with_space<int>);
std::cout << '\n';
}
int main(){
int a[] = {1, 2, 3};
std::vector<int> v(a, a+3);
print_all(v.begin(), v.end());
return 0;
}
The code compiles and runs, but only because I put print_with_space<int> inside the implementation of print_all. I would like to just have print_with_space there for obvious reasons, but then the code doesn't compile. How do I do this?
You can use:
std::for_each(beg, end, [](const typename T::value_type& value) {
print_with_space(value);
});
T is of type std::vector<>::iterator, which is a RandomAccessIterator. Every RandomAcessIterator has a underlying type, which is exposed by value_type.
So, if you pass std::vector<int>::iterator, std::vector<int>::iterator::value_type would be an int.
Now that you have the type, you can make a lambda, which will get executed for every iteration.
In C++14, you can even do:
//'auto' automatically deduces the type for you
std::for_each(beg, end, [](const auto& value) {
print_with_space(value);
});
Another option:
template <typename T> void print_all(T beg, T end) {
std::for_each(beg, end, print_with_space<decltype(*beg)>);
std::cout << '\n';
}
Alternative for C++03:
#include <iterator>
template <typename T> void print_all(T beg, T end)
{
typedef typename std::iterator_traits<T>::value_type val_t;
std::for_each(beg, end, print_with_space<val_t>);
std::cout << '\n';
}
The most flexible solution, which will work with all versions of c++, is to make print_with_space a function object.
This confers a number of advantages:
no need to specify template type at call site.
no need to fiddle around with manual type deduction.
partial specialisation can be achieved by having the functor defer to a templated free function.
Such as:
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
// basic implementation
template<class T> void impl_print_with_space(const T& x)
{
std::cout << x << ' ';
}
// what about special handling for strings?
template<class C, class Ch, class Alloc>
void impl_print_with_space(const std::basic_string<C, Ch, Alloc>& x)
{
std::cout << std::quoted(x) << ' ';
}
// functor
struct print_with_space
{
template<class T> void operator()(const T& x) const
{
impl_print_with_space(x);
}
};
template <typename Iter> void print_all(Iter beg, Iter end)
{
std::for_each(beg, end, print_with_space());
std::cout << '\n';
}
int main(){
int a[] = {1, 2, 3};
std::vector<int> v(a, a+3);
print_all(v.begin(), v.end());
auto b = std::vector<std::string> { "hello", "world" };
print_all(b.begin(), b.end());
return 0;
}
I’m writing filter and map algorithms using boost::range library:
template <class Range> struct Converter
{
Converter(const Range& p_range) : m_range(p_range) {}
template<class OutContainer> operator OutContainer() const
{
return {m_range.begin(), m_range.end()};
}
private:
Range m_range;
};
template<class Range> Converter<Range> convert(const Range& p_range) { return {p_range}; }
template<class Range, class Fun> auto map(Range&& p_range, Fun&& p_fun)
{
return convert(p_range | boost::adaptors::transformed(p_fun));
}
template<class Range, class Pred> auto filter(Range&& p_range, Pred&& p_pred)
{
return convert(p_range | boost::adaptors::filtered(p_pred));
}
Right now I can use them like this:
std::vector<int> l_in = {1, 2, 3, 4, 5};
std::vector<int> l_tmp_out = filter(l_in, [](int p){ return p < 4; });
std::vector<int> l_out = map(l_tmp_out, [](int p){ return p + 5; });
I would also like to write code this way:
map(filter(l_in, [](int p){ return p < 4; }), [](int p){ return p + 5; });
Unfortunately my Converter class does not compose with boost::range algorithms so this example does not compile. I'm looking for a proper way to change that.
UPDATE
I followed #sehe link and it turned out that all I had to do was to add this four lines to Converter class:
using iterator = typename Range::iterator;
using const_iterator = typename Range::const_iterator;
auto begin() const { return m_range.begin(); }
auto end() const { return m_range.end(); }
Here's my take on things:
Live On Coliru
#include <boost/range.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <iostream>
#include <vector>
namespace MyRange {
template <typename R> struct Proxy {
Proxy(R&& r) : _r(std::move(r)) {}
Proxy(R const& r) : _r(r) {}
template <typename OutContainer> operator OutContainer() const {
return boost::copy_range<OutContainer>(_r);
}
using iterator = typename boost::range_mutable_iterator<R>::type;
using const_iterator = typename boost::range_const_iterator<R>::type;
auto begin() const { return range_begin(_r); }
auto end() const { return range_end(_r); }
auto begin() { return range_begin(_r); }
auto end() { return range_end(_r); }
private:
R _r;
};
template <typename R> auto make_proxy(R&& r) { return Proxy<R>(std::forward<R>(r)); }
template <typename Range, typename Fun> auto map(Range&& p_range, Fun&& p_fun) {
return make_proxy(std::forward<Range>(p_range) | boost::adaptors::transformed(std::forward<Fun>(p_fun)));
}
template <typename Range, typename Pred> auto filter(Range&& p_range, Pred&& p_pred) {
return make_proxy(std::forward<Range>(p_range) | boost::adaptors::filtered(std::forward<Pred>(p_pred)));
}
}
int main() {
using namespace MyRange;
{
std::vector<int> l_in = {1, 2, 3, 4, 5};
std::vector<int> l_tmp_out = filter(l_in, [](int p){ return p < 4; });
std::vector<int> l_out = map(l_tmp_out, [](int p){ return p + 5; });
boost::copy(l_out, std::ostream_iterator<int>(std::cout << "\nfirst:\t", "; "));
}
{
boost::copy(
map(
filter(
std::vector<int> { 1,2,3,4,5 },
[](int p){ return p < 4; }),
[](int p){ return p + 5; }),
std::ostream_iterator<int>(std::cout << "\nsecond:\t", "; "));
}
}
Prints
first: 6; 7; 8;
second: 6; 7; 8;
NOTES
it uses std::forward<> more accurately
it uses const/non-const iterators
it uses Boost Range traits (range_mutable_iterator<> etc.) instead of hardcoding assuming nested typedefs. This allows things to work with other ranges (e.g. std::array<> or even int (&)[]).
the user-defined converson operator uses boost::copy_range<> for similar reasons