14

次のコードを使用します(元のコードの煮詰めたバージョン)

#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
}

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 と合わせて、最終的に問題を修正しまし。の定義の にはforが必要です。これは、最初のコンテキストでプライベートな を使用します。decltype()dist()decltype()A<X>::diff()A<X>::a

EDTI4 : Rook の使用の提案typename std::common_type<X,Y>::typeも有効です!

EDIT5 :しかし、この質問に対するJonathan Wakelyの回答を参照してください

4

5 に答える 5

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 のバグのように見えます。

A<X>他の人はとが異なるクラスであると述べていA<Y>ますが、ここではそうではなく、両方とも ですA<double>。これは、この場合、友情は必要ないことを意味すると思いますが、一般的なケースで働くにはA<X>、Aの他の専門分野と友達になる必要があります.

具体的には、ainy.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);
}

このコードは、gcc 4.5 で説明したのと同様のビルド エラーを引き起こします。

交換する

auto diff(A<Y> const&y) const -> decltype(a-y.a)

auto diff(A<Y> const&y) const -> typename std::common_type<X,Y>::type

コードがgcc 4.5 で動作するようにします。

これは、gcc が末尾の戻り値の型をクラスのスコープ内として処理できないというバグを示しています。一部のテストでは、バグをトリガーするには、末尾の戻り値の型がテンプレート関数にある必要があることが明らかになりました。

于 2012-06-15T14:44:38.977 に答える
8

コードにエラーがあります:

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

ここでA<Y>は、型が異なるため、データ メンバであるA<X>ことがわかりません。aしかA<Y>見えないA<Y>::a

編集:それは、あなたの特定のケースでは、XYは両方doubleであるため、それがコンパイルされることを素朴に期待しています。最良の場合、この構造はXYが同じ場合にのみコンパイルする必要があることに注意してください。

于 2012-06-15T14:45:13.920 に答える
2

関数は、ステートメント内のクラスの外部から変数にauto diff(A<Y> const& y)アクセスします。privateA::adecltype

関数で行う方法で使用する場合は、そうする必要がありA::aます。publicdiff

編集:友情の解決策は、この問題にはるかに適しているようで、公開するだけです。

于 2012-06-15T14:46:19.677 に答える
2

auto diff(A<Y> const&y) const -> decltype(a-y.a)問題です。なんといっても、 と がタイプが違えば、と がタイプXが違い、お互いのプライベートをのぞき見ることができない。テンプレートは共変ではありません!YA<X>A<Y>

Xここでの特定のエラーは、GCC の風変わりである可能性があります (それが と同じ型であることを認識しないという点でY) が、2 つの異なる型を比較しようとしている可能性があるより一般的なケースです (そうでなければ、別のテンプレートを用意する必要があります)。 diff 関数を入力しますか?) は、コンパイラに関係なく機能しません。

于 2012-06-15T14:53:56.523 に答える
0

私が今までに理解したように(質問の編集も参照)、問題は何でしたか。(これまでのところ)すべての回答が(完全な)問題を解決していないことがわかりました。

基本的にdecltype、グローバル関数の式の評価には、最終的にプライベート メンバーが必要でした( の式でのA<X>::a出現により)。これは、これについて標準が何を述べているかについての次の質問を開きます。decltypeA<x>::diff()

于 2012-06-15T15:37:12.993 に答える