【问题标题】:error: binding ‘const double’ to reference of type ‘double&’ discards qualifiers错误:将“const double”绑定到“double&”类型的引用会丢弃限定符
【发布时间】:2018-01-09 03:30:54
【问题描述】:

我收到错误

将“const double”绑定到“double&”类型的引用会丢弃限定符

编译时:

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})
                            ^

虽然网上还有其他关于这个错误的问题,但我正在寻找这个特定代码的解决方案。我坚持使用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;
}

【问题讨论】:

  • 为什么要通过P?为什么不P.square()
  • @stark,这是一个 MWE,实际上功能更加定制化。将函数放在类中是不值得的。 BTW,一个方法也会有类似的问题,不是吗?
  • I insist on using ranged for. .. 为什么?
  • @txtechhelp,否则我应该多次编写代码。
  • 多次写什么代码?您正在修改一个不会修改任何内容的临时变量。您是否打算将 3 个变量倍增,例如double t = x * y * z;?从您的代码中不清楚您实际上要做什么,以及为什么必须使用范围 for 循环。

标签: c++ c++11 ranged-loops


【解决方案1】:

{Q.x,Q.y,Q.z} 在您的for 上下文中创建的初始化列表仍然基于单独的值数组。即使您以某种方式设法修改了这些值,它仍然不会影响您的Q,这显然是您的意图。但是无论如何您都无法修改它们,因为该数组由 const 元素组成(这是编译器告诉您的)。

如果您想要远程for,您可以使用旧的 C 时代技巧

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

或者,或者

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

【讨论】:

  • 后面使用std::ref的代码有额外开销吗?
  • @ar2015:理论上是可以的。但是,在任何自尊的实施中,都没有可信的理由。
  • 如果我使用double &amp;而不是auto是否正确?
  • @ar2015:是的,当然。 std::reference_wrapper 确实有到存储引用类型的转换运算符。
【解决方案2】:

当然正确答案是:

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

定义如下:

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;});
}

参考:https://codereview.stackexchange.com/a/67394/82510

【讨论】:

  • @ar2015,我回答的重点是说如果x,y,z是同一个类型,那么最好用std::array&lt;double, 3&gt;来表示或者包裹Point,也就是已经是一个可以迭代的容器(使用for 范围)。计算几何通常定义数量 enum {X, Y, Z} 以访问 p[X], p[Y], p[Z] 如果这是您要使用的符号 (cs.smith.edu/~jorourke/books/compgeom.html) 。另一方面,如果 x、y、z 是不同的类型(不是您的情况),那么这个答案基本上是唯一的解决方案。
猜你喜欢
  • 2015-11-29
  • 2018-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
相关资源
最近更新 更多