在C++ 11中使用decltype()时出错(在gcc 4.7.0中创建不透明的错误消息)

Wal*_*ter 14 c++ decltype auto c++11

使用以下代码(我的原始代码的简化版本)

#include <iostream>
#include <cmath>

template <typename> class A;                  // edit 1 following Mark & Matthieu
template <typename X> class A {
  X a;
  template <typename> friend class A;         // edit 1 following Mark & Matthieu
public:
  A(X x) : a(x) {}
  X get() const { return a; }                // edit 2 to avoid using A<Y>::a
  template <typename Y>
  auto diff(A<Y> const& y) const
    -> decltype(a - y.a)                       // original code causing error with gcc
    -> typename std::common_type<X, Y>::type  // alternative following Rook
    -> decltype(this->get() -                 // edit 3 not using A<X>::a
                y.get())                     // edit 2 not using A<Y>::a
  { return a - y.get(); }
};

template <typename X, typename Y>
inline auto dist(A<X> const& x, A<Y> const& y) -> decltype(std::abs(x.diff(y)))
{ return std::abs(x.diff(y)); }

int main()
{
  A<double> x(2.0), y(4.5);
  std::cout << " dist(x,y)=" << dist(x,y) << '\n'; // <-- error here
}
Run Code Online (Sandbox Code Playgroud)

我用gcc 4.7.0得到以下错误:

test.cc:在函数decltype (std::abs(x.diff(y))) dist(const A<X>&, const A<Y>&)[with X = double; Y = double; decltype (std::abs(x.diff(y))) = double]'中:

test.cc:5:5:错误:double A<double>::a是私有的

突出显示的行:错误:在此上下文中

此错误消息显然不是很有帮助.我的代码中有错误吗?或者这是编译器的问题?

EDIT1:朋友声明没有帮助.

EDIT2:避免使用A<Y>::a也没有帮助.

EDIT3:与EDIT2一起终于修复了问题.该decltype()定义中的dist()要求decltype()A<X>::diff(),这反过来使用A<X>::a,这是在第一上下文私人.

EDTI4:Rook的使用建议typename std::common_type<X,Y>::type也有效!

EDIT5:但是看看Jonathan Wakely对这个问题的回答

bam*_*s53 9

TL; DR: Gcc 似乎有一个错误,其中模板成员函数上的尾随返回类型不被视为类的范围.

这个错误导致gcc在实例化模板成员函数时失败,auto diff(A<Y> const&y) const -> decltype(a-y.a)因为它a是私有的,而gcc认为私有成员在这里是不可访问的.


代码使用clang和VC++构建得很好,我没有看到任何试图访问A<double>::a外部的东西A<double>,所以它看起来像是一个gcc bug.

其他人已经提到A<X>并且A<Y>是不同的类别,但这不是这里的情况,两者都是A<double>.我认为这意味着在这种情况下友谊是不必要的,虽然在一般情况下工作A<X>确实需要与A的其他专业成为朋友.

具体来说,ain y.a是一个从属名称,因此A<Y>在知道之前无法查找.在那时完成查找,测试可访问性并且应该找到可A<double>访问的可访问性A<double>::a.

这是我在clang(svn-3.2)和VC++ 11中编译的确切代码(因为我在Windows上使用clang我不能#include <iostream>)

#include <cmath>

template<typename X> class A {
  X a;
public:
  A(X x) : a(x) {}
  template<typename Y>
  auto diff(A<Y> const&y) const -> decltype(a-y.a)
  { return a-y.a; }
};

template<typename X, typename Y>
inline auto dist(A<X> const&x, A<Y> const&y) -> decltype(std::abs(x.diff(y)))
{ return std::abs(x.diff(y)); }

int main()
{
  A<double> x(2.0), y(4.5);
  return (int) dist(x,y);
}
Run Code Online (Sandbox Code Playgroud)

此代码导致gcc 4.5上的构建错误与您描述的类似.

更换

auto diff(A<Y> const&y) const -> decltype(a-y.a)
Run Code Online (Sandbox Code Playgroud)

auto diff(A<Y> const&y) const -> typename std::common_type<X,Y>::type
Run Code Online (Sandbox Code Playgroud)

导致代码在gcc 4.5上运行.

这向我指出了一个错误,即gcc无法将尾随返回类型视为类的范围内部.一些测试显示尾随返回类型必须在模板函数上才能触发错误.

  • 不,看到其他答案.只是"A <X>"和"A <Y>"是不同的类型,所以他们无法访问彼此的私人成员 (2认同)
  • 我认为这是这个错误http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52816 (2认同)

jua*_*nza 8

您的代码出错:

template<typename Y>
  auto diff(A<Y> const&y) const -> decltype(a-y.a)
  { return a-y.a; }
Run Code Online (Sandbox Code Playgroud)

这里A<Y>是一个不同的类型,所以A<X>无法看到它的a数据成员.只能A<Y>看到A<Y>::a.

编辑:这么说,你的具体情况,X并且Y都是double,所以我会天真地期望编译.请注意,在最好的情况下,这种结构应该只编译时XY是一样的,你想要什么这可能不是.

  • 这是我的第一个想法,但我有点怀疑,因为在他的特殊情况下(没关系,你的编辑说的正是我要说的) (2认同)