error: binding ‘const double’ to reference of type ‘double&’ discards qualifiers

5.5k Views Asked by At

I receive error

binding ‘const double’ to reference of type ‘double&’ discards qualifiers

when compiling:

g++ -std=c++11 main.cpp
main.cpp: In function ‘Point square(const Point&)’:
main.cpp:14:28: error: binding ‘const double’ to reference of type ‘double&’ discards qualifiers
  for(double &a:{Q.x,Q.y,Q.z})
                            ^

While there are other questions online about this error, I am looking for a solution this particular code. I insist on using ranged for.

#include <iostream>
#include <vector>

class Point
{
public:
    double x,y,z;
};

Point square(const Point &P)
{
    Point Q=P;
    for(double &a:{Q.x,Q.y,Q.z})
        a*=a;
    return Q;
}

int main()
{
    Point P{0.1,1.0,10.0};
    Point Q=square(P);
    std::cout<<"----------------"<<std::endl;
    std::cout<<"Q.x: "<<Q.x<<std::endl;
    std::cout<<"Q.y: "<<Q.y<<std::endl;
    std::cout<<"Q.z: "<<Q.z<<std::endl;
    std::cout<<"----------------"<<std::endl;
    return 0;
}
2

There are 2 best solutions below

4
On BEST ANSWER

An initializer list created by {Q.x,Q.y,Q.z} in context of your for is still based on a separate array of values. Even if you somehow managed to modify these values, it still wouldn't affect your Q, which is apparently your intent. But you can't modify them anyway, since that array consists of const elements (which is what the compiler is telling you).

If you want a ranged for you can use an old C-era trick

for (double *a : { &Q.x, &Q.y, &Q.z })
  *a *= *a;

or, alternatively

for (auto a : { std::ref(Q.x), std::ref(Q.y), std::ref(Q.z) })
  a *= a;
1
On

Of course the correct answer is:

for_each(std::tie(x, y, z), [](auto& a){a *= a;});

Defined as follow:

template <typename Tuple, typename F, std::size_t ...Indices>
void for_each_impl(Tuple&& tuple, F&& f, std::index_sequence<Indices...>) {
    using swallow = int[];
    (void)swallow{1,
        (f(std::get<Indices>(std::forward<Tuple>(tuple))), void(), int{})...
    };
}
template <typename Tuple, typename F>
void for_each(Tuple&& tuple, F&& f) {
    constexpr std::size_t N = std::tuple_size<std::remove_reference_t<Tuple>>::value;
    for_each_impl(std::forward<Tuple>(tuple), std::forward<F>(f),
                  std::make_index_sequence<N>{});
}

int main(){
    double x, y, z;
    for_each(std::tie(x, y, z), [](auto& a){a *= a;});
}

Reference: https://codereview.stackexchange.com/a/67394/82510