I have a function which looks like this:
template <typename T, std::size_t... I>
std::ostream& vector_insert(std::ostream& lhs, const char* delim, const T& rhs, std::index_sequence<I...>) {
std::ostream_iterator<float> it(lhs, delim);
((*it++ = at(rhs, I)), ...);
return lhs;
}
This is my final attempt and I'm still failing on my expansion of the integer_sequence I'm hoping someone can tell me how to write a line that will effectively expand to:
*it++ = at(rhs, 0U), *it++ = at(rhs, 1U), *it++ = at(rhs, 2U)
Other things I've tried are:
*it++ = at(rhs, I...)
*it++ = at(rhs, I)...
(*it++ = at(rhs, I))...
All of them are giving me the error:
error C3520: I: parameter pack must be expanded in this context
How do I expand this thing?
EDIT:
#AndyG has pointed out that this seems to be a visual-studio-2017 bug.
This seems like a compiler bug with Visual C++. I'm not aware of any easy fix for it other than simplifying the expression in which the parameter pack is expanded. Converting to a recursive approach seems to reliably work around the problem. For example :
#include <array>
#include <iostream>
#include <iterator>
template <typename T>
const auto& at(const T& v, size_t i) { return v[i]; }
// End of recursion
template<class T>
void vector_insert_impl(std::ostream_iterator<int> &, const char*, const T&)
{}
// Recursion case
template<class T, std::size_t N, std::size_t... I>
void vector_insert_impl(std::ostream_iterator<int> & iter, const char* delim, const T&rhs)
{
*iter++ = at(rhs, N);
// Continue the recursion
vector_insert_impl<T, I...>(iter, delim, rhs);
}
template <typename T, std::size_t... I>
std::ostream& vector_insert(std::ostream& lhs, const char* delim, const T& rhs, std::index_sequence<I...>)
{
std::ostream_iterator<int> it(lhs, delim);
// Call the recursive implementation instead
vector_insert_impl<T, I...>(it, delim, rhs);
return lhs;
}
int main() {
std::array<int, 5> v = { 1, 2, 3, 4, 5 };
vector_insert(std::cout, " ", v, std::make_index_sequence<v.size()>());
}
Here, the parameter pack I is only expanded in the context of providing template parameters which VC++ has no trouble with.
Related
I've defined a template function called "Equals()" to compare integer constants between 2 std::array, or compare with a c-style array, like below:
template<typename T, typename U, size_t M, size_t N>
constexpr bool EqualsImpl(const T& lhs, const U& rhs)
{
static_assert(M == N);
for (size_t i = 0; i < M; ++i) {
if (lhs[i] != rhs[i]) {
return false;
}
}
return true;
}
template<typename T, typename U>
constexpr bool Equals(const T& lhs, const U& rhs)
{
return EqualsImpl<T, U, size(lhs), size(rhs)>(lhs, rhs);
}
template<typename T, typename U, size_t N>
constexpr bool Equals(const T& lhs, const U (&rhs)[N])
{
return EqualsImpl<T, const U (&)[N], size(lhs), N>(lhs, rhs);
}
int main(int argc, char* argv[]) {
constexpr std::array<int, 4> before{1, 2, 3, 4};
constexpr std::array<int, 4> after = {1, 2, 3, 4};
static_assert(Equals(after, {1, 2, 3, 4}));//fail to compile
static_assert(!Equals(before, after));//fail to compile
return 0;
}
g++ compile with --std=c++20 and prints error message:
error: no matching function for call to 'EqualsImpl'
return EqualsImpl<T, U, size(lhs), size(rhs)>(lhs, rhs);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: in instantiation of function template specialization 'Equals<std::array<int, 4>, std::array<int, 4>>' requested here
static_assert(!Equals(before, after));
note: candidate template ignored: invalid explicitly-specified argument for template parameter 'M'
constexpr bool EqualsImpl(const T& lhs, const U& rhs)
error: static_assert expression is not an integral constant expression
static_assert(!Equals(before, after));
^~~~~~~~~~~~~~~~~~~~~~
How to fix my code to make it work? Thanks.
I would like to implement some lazy evaluation in my code. Here is a snippet representative of what I would like to do:
#include <Eigen/Dense>
#include <iostream>
template <int N, int M>
struct S {
template <typename T>
S &operator=(const T &src) {
v = src();
return *this;
}
Eigen::Matrix<double, N, M> v;
};
// If I comment this one the code compiles
template <typename Lhs, typename Rhs>
auto operator+(const Lhs &lhs, const Rhs &rhs) {
return [&]() { return lhs() + rhs(); };
}
template <typename Lhs, int N, int M>
auto operator+(const Lhs &lhs, const S<N, M> &s) {
return [&]() { return lhs() + s.v; };
}
template <typename Rhs, int N, int M>
auto operator+(const S<N, M> &s, const Rhs &rhs) {
return [&]() { return s.v + rhs(); };
}
template <int N0, int M0, int N1, int M1>
auto operator+(const S<N0, M0> &s0, const S<N1, M1> &s1) {
return [&]() { return s0.v + s1.v; };
}
int main() {
static constexpr int n = 4;
S<n, n> s0, s1;
S<Eigen::Dynamic, Eigen::Dynamic> s2;
s1.v = 2. * Eigen::Matrix<double, n, n>::Ones();
s2.v = 3. * Eigen::Matrix<double, n, n>::Ones();
s0 = s1 + s2;
std::cout << s0.v << std::endl;
return 0;
}
I got a compilation error which relates to the fact that when implementing s1 + s2, the first overload of the + operator is selected (and if I comment it, the code works). It seems that for the compiler the first one is considered as the more specialized, whereas to my common sense the last one is the more specialized: the first one accepts whatever arguments, whereas the last one only accepts type related to the template class S.
What is the explanation to that? How can I fix this snippet to make it work while keeping the first overload (which will be required for the lazy evaluation of 'nested' expressions)?
Many thanks!
EDIT: from the answer and comments, I now understand that the problem is related to a conflict between the first overload of the + operator in the snippet and the some overload of the + operator in the Eigen library. The simplified snippet following illustrate that:
#include <Eigen/Dense>
#include <iostream>
template <typename Lhs, typename Rhs>
auto operator+(const Lhs &lhs, const Rhs &rhs) {
return [&]() { return lhs() + rhs(); };
}
int main() {
Eigen::Matrix<double, 4, 4> m0, m1, m2;
m2=m0+m1;
return 0;
}
Here, the + operator of the snippet is selected, whereas I expected that one of the Eigen's would be selected... Why is that?
It looks like the first overload is selected, but not for s1 + s2. That selects the 4th overload. However, inside that 4th overload you have s0.v + s1.v;, and .v is not an S<N, M>
The following code is based on that found in Modern C++ programming cookbook, and is compiled in VS 2017:
#include <iostream>
using namespace std;
template <typename T, size_t const Size>
class dummy_array
{
T data[Size] = {};
public:
T const & GetAt(size_t const index) const
{
if (index < Size) return data[index];
throw std::out_of_range("index out of range");
}
// I have added this
T & GetAt(size_t const index)
{
if (index < Size) return data[index];
throw std::out_of_range("index out of range");
}
void SetAt(size_t const index, T const & value)
{
if (index < Size) data[index] = value;
else throw std::out_of_range("index out of range");
}
size_t GetSize() const { return Size; }
};
template <typename T, typename C, size_t const Size>
class dummy_array_iterator_type
{
public:
dummy_array_iterator_type(C& collection,
size_t const index) :
index(index), collection(collection)
{ }
bool operator!= (dummy_array_iterator_type const & other) const
{
return index != other.index;
}
T const & operator* () const
{
return collection.GetAt(index);
}
// I have added this
T & operator* ()
{
return collection.GetAt(index);
}
dummy_array_iterator_type const & operator++ ()
{
++index;
return *this;
}
private:
size_t index;
C& collection;
};
template <typename T, size_t const Size>
using dummy_array_iterator = dummy_array_iterator_type<T, dummy_array<T, Size>, Size>;
// I have added the const in 'const dummy_array_iterator_type'
template <typename T, size_t const Size>
using dummy_array_const_iterator = const dummy_array_iterator_type<T, dummy_array<T, Size> const, Size>;
template <typename T, size_t const Size>
inline dummy_array_iterator<T, Size> begin(dummy_array<T, Size>& collection)
{
return dummy_array_iterator<T, Size>(collection, 0);
}
template <typename T, size_t const Size>
inline dummy_array_iterator<T, Size> end(dummy_array<T, Size>& collection)
{
return dummy_array_iterator<T, Size>(collection, collection.GetSize());
}
template <typename T, size_t const Size>
inline dummy_array_const_iterator<T, Size> begin(dummy_array<T, Size> const & collection)
{
return dummy_array_const_iterator<T, Size>(collection, 0);
}
template <typename T, size_t const Size>
inline dummy_array_const_iterator<T, Size> end(dummy_array<T, Size> const & collection)
{
return dummy_array_const_iterator<T, Size>(collection, collection.GetSize());
}
int main(int nArgc, char** argv)
{
dummy_array<int, 10> arr;
for (auto&& e : arr)
{
std::cout << e << std::endl;
e = 100; // PROBLEM
}
const dummy_array<int, 10> arr2;
for (auto&& e : arr2) // ERROR HERE
{
std::cout << e << std::endl;
}
}
Now, the error is pointing at the line
T & operator* ()
stating
'return': cannot convert from 'const T' to 'T &'"
...which is raised from my range based for loop on arr2.
Why is the compiler choosing the none-constant version of operator*()?. I have looked at this for a long time; I think its because it thinks that the object on which it is calling this operator is not constant: this should be a dummy_array_const_iterator. But, this object has been declared to be constant via
template <typename T, size_t const Size>
using dummy_array_const_iterator = const dummy_array_iterator_type<T, dummy_array<T, Size> const, Size>;
...so I really don't understand what is happening. Can someone please clarify?
TIA
dummy_array_const_iterator::operator * should always return T const & regardless of constness of the iterator object itself.
The easiest way to achieve this is probably just to declare it with T const as underlying iterator value type:
template <typename T, size_t const Size>
using dummy_array_const_iterator = dummy_array_iterator_type<T const, dummy_array<T, Size> const, Size>;
Since you are returning the iterator by value its constness can be easily lost by c++ type deduction rules and just declaring dummy_array_const_iterator as alias to const dummy_array_iterator_type is not enough. i.e. the following fails:
#include <type_traits>
struct I { };
using C = I const;
C begin();
int bar()
{
auto x = begin(); // type of x is deduced as I
static_assert(std::is_same<I, decltype(x)>::value, "same"); // PASS
static_assert(std::is_same<decltype(begin()), decltype(x)>::value, "same"); // ERROR
}
I found a way to enable T& operator*() only when C is not constant:
template <class Tp = T>
typename std::enable_if<std::is_const<C>::value, Tp>::type const& operator* () const
{
return collection.GetAt(index);
}
template <class Tp = T>
typename std::enable_if<!std::is_const<C>::value, Tp>::type & operator* () const
{
return collection.GetAt(index);
}
I have no idea about the syntax (which I get from https://stackoverflow.com/a/26678178)
In my projects I'm using boost-variant exhaustively. Hence, for my unit tests I need to check the contents of a variant against a certain T with a certain content t.
So I deviced the function cmpVariant for this sole purpose and to remove clutter from my unit tests.
In some cases the type T is not equipped with an operator==, so that the user might pass a function satisfying the EqualityCompare Requirement (https://en.cppreference.com/w/cpp/named_req/EqualityComparable)
Now for some obscure reason the following code fails to compile. It says, that there is no matching function?
Clang 6.0.1 Compiler Error
prog.cc:22:5: error: no matching function for call to 'cmpVariant'
cmpVariant(number, 3.2, lambdaEquiv); // Fails!
^~~~~~~~~~
prog.cc:6:6: note: candidate template ignored: could not match 'function<bool (const type-parameter-0-1 &, const type-parameter-0-1 &)>' against '(lambda at prog.cc:19:24)'
bool cmpVariant(
^
1 error generated.
Does anyone knows why?
Code
#include <iostream>
#include <boost/variant.hpp>
#include <functional>
template<typename V, typename T>
bool cmpVariant(
const V& variant,
const T& t,
const std::function<bool(const T& u, const T& v)>& equiv = [](const T& u, const T& v) {return u == v; })
{
if (variant.type() != typeid(t)) return false;
auto v = boost::get<T>(variant);
return equiv(v, t);
}
int main(int, char**) {
boost::variant<double, int> number{ 3.2 };
cmpVariant(number, 3.2);
auto lambdaEquiv = [](const double& x, const double& y) { return x == y; };
std::function<bool(const double&, const double&)> equiv = lambdaEquiv;
cmpVariant(number, 3.2, equiv); // Works!
cmpVariant(number, 3.2, lambdaEquiv); // Fails!
}
The compiler is not able to match the lambda to the function parameter type. You can fix this by explicitly instantiating the function call:
cmpVariant<boost::variant<double, int>, double>(number, 3.2, equiv);
This is clearly a bit wordy, so here is another possibility changing your function declaration to
template<typename V, typename T, typename Fct = std::function<bool(const T& u, const T& v)>>
bool cmpVariant(
const V& variant,
const T& t,
Fct&& f = [](const T& u, const T& v) {return u == v; })
{ /* Same as before. */ }
which can be called like this
cmpVariant(number, 3.2, equiv); // Type deduction works now.
An improvement suggested by #DanielLangr in the comments is to employ std::equal_to.
template<typename V, typename T, typename Fct = std::equal_to<T>>
bool cmpVariant(
const V& variant,
const T& t,
Fct&& f = std::equal_to<T>{})
{ /* Again, same as before. */ }
One advantage here is to get rid of std::function and its often unnecessary overhead.
The way comparator argument is accepted makes deduction problematic, so you may want to change comparator into template parameter (possibly avoiding construction of heavy std::function object ):
template<typename T> class t_EquilityComparator
{
public: bool operator ()(const T& u, const T& v) const { return u == v; }
};
template<typename V, typename T, typename Comparator = t_EquilityComparator<T>>
bool cmpVariant(
const V& variant,
const T& t,
const Comparator & equiv = Comparator{})
{
if (variant.type() != typeid(t)) return false;
auto v = boost::get<T>(variant);
return equiv(v, t);
}
int main(int, char**) {
boost::variant<double, int> number{ 3.2 };
cmpVariant(number, 3.2);
auto equiv = [](const double& x, const double& y) { return x == y; };
cmpVariant(number, 3.2, equiv); // This line fails to compile! Why?
}
online compiler
I'm rewriting the vector math portion of my project, and I'd like to generalize vectors by their type and number of dimensions. A vector<T, N> represents an N dimensional vector of type T.
template<typename T, int N>
struct vector {
T data[N];
};
I'll need to rewrite many math functions, most of which will operate on a per-component basis. The straightforward implementation of the addition operator is shown below.
template<typename T, int N>
vector<T, N> operator+(vector<T, N> lhs, vector<T, N> rhs) {
vector<T, N> result;
for (int i = 0; i < N; i++) {
result[i] = lhs[i] + rhs[i];
}
return result;
}
My question: Is there a way (via template-trickery?) to implement this without the use of a for loop and a temporary variable? I understand that the compiler would most likely unroll the loop and optimize it away. I just don't like the idea of having all of my performance-critical math functions implemented this way. They will all be inlined and in the header, so having many of these functions would also make for a big ugly header file.
I'm wondering if there is a way to do this which would produce more optimal source code. Possibly a way that works like variadic templates do. Something along the lines of this.
template<typename T, int N>
vector<T, N> operator+(vector<T, N> lhs, vector<T, N> rhs) {
return vector<T, N>(lhs[0] + rhs[0], lhs[1] + rhs[1]...);
}
One way to do this is via lower level "map" functions:
Here's a complete working example
#include <iostream>
#include <math.h>
template<typename T, int N>
struct vector {
T data[N];
};
First declare your worker "map" functions - I've got 3 here map, map2, foreach.
template<typename T, int N, typename FN>
static void foreach(const vector<T,N> & vec, FN f) {
for(int i=0; i<N ;++i) {
f(vec.data[i]);
}
}
template<typename T, int N, typename FN>
static auto map(const vector<T,N> & vec, FN f) -> vector<decltype(f(T(0))), N> {
vector<decltype(f(T(0))), N> result;
for(int i=0; i<N ;++i) {
result.data[i] = f(vec.data[i]);
}
return result;
}
template<typename T1, typename T2, int N, typename FN>
static auto map2(const vector<T1,N> & vecA,
const vector<T2,N> & vecB,
FN f)
-> vector<decltype(f(T1(0), T2(0))), N> {
vector<decltype(f(T1(0), T2(0))), N> result;
for(int i=0; i<N ;++i) {
result.data[i] = f(vecA.data[i], vecB.data[i]);
}
return result;
}
Now use the helpers to define your higher level functions via lambdas. I'll define binary +, binary -, unary - and e^x. Oh and operator<< so we can see what is going on.
I'm pretty sure there's a better alternative to the lambdas used in operator+ and operator-, but I can't remember them
template<typename T, int N>
vector<T,N> operator+(const vector<T,N> &lhs, const vector<T,N> &rhs) {
return map2(lhs, rhs, [](T a,T b) { return a+b;} );
}
template<typename T, int N>
vector<T,N> operator-(const vector<T,N> &lhs, const vector<T,N> &rhs) {
return map2(lhs, rhs, [](T a,T b) { return a-b;} );
}
template<typename T, int N>
vector<T,N> operator-(const vector<T,N> &vec) {
return map(vec, [](T a) { return -a;} );
}
template<typename T, int N>
auto exp(const vector<T,N> &vec) -> vector<decltype(exp(T(0))), N> {
return map(vec, [](T a) { return exp(a); } );
}
template<typename T, int N>
std::ostream & operator<<(std::ostream& os, const vector<T,N> &vec) {
os<<"{";
foreach(vec, [&os](T v) { os<<v<<", "; } );
os<<"}";
return os;
}
Now look how they work just fine...
int main() {
vector<int, 5> v1 = {1,2,3,4,5};
vector<int, 5> v2 = {2,4,6,8,10};
std::cout<<v1 << " + " << v2 << " = " << v1+v2<<std::endl;
std::cout<<v1 << " - " << v2 << " = " << v1-v2<<std::endl;
std::cout<<" exp( - " << v2 << " )= " << exp(-v1)<<std::endl;
}
You can do this and I'll point you towards a solution (which compiles and runs). You are looking to get rid of the loop, preferably by inlining it in hopes the compiler will optimize things for you.
In practice I have found it sufficient to specify the dimensions needed, i.e. N = 3, 4, 5 because this allows finer grained control over what the compiler does than doing what you asked for. However you can use recursion and partial template specialization to implement your operators. I have illustrated addition.
So instead of this:
template<typename T, int N>
vector<T, N> operator+(vector<T, N> lhs, vector<T, N> rhs) {
vector<T, N> result;
for (int i = 0; i < N; i++) {
result[i] = lhs[i] + rhs[i];
}
return result;
}
You want code that effectively does this:
template<typename T, int N>
vector<T, N> operator+(vector<T, N> lhs, vector<T, N> rhs) {
vector<T, N> result;
result[0] = lhs[0] + rhs[0];
result[1] = lhs[1] + rhs[1];
...
result[N-1] = lhs[N-1] + rhs[N-1];
return result;
}
if N is 1, it is pretty easy you just want this...
template
vector operator+(vector lhs, vector rhs) {
vector result;
result[0] = lhs[0] + rhs[0];
return result;
}
and if N is 2, it is pretty easy you just want this...
template
vector operator+(vector lhs, vector rhs) {
vector result;
result[0] = lhs[0] + rhs[0];
result[1] = lhs[1] + rhs[1];
return result;
}
The easiest way is to simply define this up to as many N as you expect to use and not the answer you are looking for because you probably don't need more than N=5 or N=6 in practice right?
However, you can also use partial template specialization and recursion to get there. Consider this struct, which recursively calls itself and then assigns the index:
template<typename T, int N, int IDX>
struct Plus
{
void operator()(vector<T,N>& lhs, vector<T,N>& rhs, vector<T,N>& result)
{
Plus<T,N,IDX-1>()(lhs,rhs,result);
result.data[IDX] = lhs.data[IDX] + rhs.data[IDX];
}
};
and this partial specialization which appears to do nothing, but handles the case when the index is 0 and ends the recursion:
template<typename T, int N>
struct Plus<T,N,-1>
{
void operator()(vector<T,N>& lhs, vector<T,N>& rhs, vector<T,N>& result)
{
//noop
}
};
and finally this implementation of operator+ which instantiates Plus and calls it:
template<typename T, int N>
vector<T, N> operator+(vector<T, N> lhs, vector<T, N> rhs) {
vector<T, N> result;
Plus<T,N,N-1>()(lhs,rhs,result);
return result;
}
You'll need to turn this into an operator to make it more general purpose but you get the idea. However this is mean to the compiler and it may take awhile in big projects even if it is super cool. In practice I have found that hand typing the overloads you want or writing script code to generate the C++ results in a more debuggable experience and code that in the end is simpler to read and easier for the compiler to optimize. More specifically if you write a script to generate the C++ you can include the SIMD intrinsics in the first place and not leave things to chance.
Firstly, compiler would probably unroll the loop.
Secondly, for better performance, pass your argument by const reference instead of by value to avoid extra copies.
And to answer your question, you may use std::index_sequence to construct in place, something like:
namespace detail
{
template<typename T, int N, std::size_t...Is>
vector<T, N> add(std::index_sequence<Is...>,
const vector<T, N>& lhs,
const vector<T, N>& rhs)
{
return {{ (lhs[Is] + rhs[Is])... }};
}
}
template<typename T, int N>
vector<T, N> operator+(const vector<T, N>& lhs, const vector<T, N>& rhs) {
return detail::add(std::make_index_sequence<N>{}, lhs, rhs);
}
Demo