4

Visual C ++ 2010のバグですか、それとも正しい動作ですか?

template<class T>
T f(T const &r)
{
    return r;
}

template<class T>
T f(T &&r)
{
    static_assert(false, "no way"); //< line # 10
    return r;
}

int main()
{
    int y = 4;
    f(y); //< line # 17
}

関数f(T &&)は決して呼び出されるべきではないと思いましたが、T = int&で呼び出されます。出力:

    main.cpp(10):エラーC2338:まさか
          main.cpp(17):コンパイルされている関数テンプレートのインスタンス化'T f(T)'への参照を参照してください
          と
          [
              T = int&
          ]

アップデート1リファレンスとしてC++x0コンパイラを知っていますか?comeauオンラインテストドライブを試しましたが、r値参照をコンパイルできませんでした。

アップデート2の回避策(SFINAEを使用):

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_reference.hpp>

template<class T>
T f(T &r)
{
    return r;
}

template<class T>
typename ::boost::disable_if< ::boost::is_reference<T>, T>::type f(T &&r)
{
    static_assert(false, "no way");
    return r;
}

int main()
{
    int y = 4;
    f(y);
    // f(5); // generates "no way" error, as expected.
}

アップデート3一部のコンパイラは、関数テンプレートのインスタンス化がない場合でも、static_assert(false、 "no way")でトリガーします。回避策(@Johannes Schaubに感謝-litb)

template<class T> struct false_ { static bool const value = false; };
...
static_assert(false_<T>::value, "no way");

また

static_assert(sizeof(T) == sizeof(T), "no way");
4

2 に答える 2

5

私が理解しているように(そして私は完全に正しくないかもしれません;仕様は少し複雑です)、テンプレートタイプの推論ルールはあなたに対して陰謀を企てます。

コンパイラは最初にすべてのテンプレートを置き換えようとし(現時点ではまだ選択されていません。オプションを探しているだけです)、次のようになります。

  • T const &rint左辺値をと一致させT = int、作成しますf(int const &)
  • T &&rint左辺値をT = int&と一致させ、にint & &&還元してint&作成します(仕様f(int &)にはこれを示す規則があります)。

ここで、正しいオーバーロードを選択することになります。前者はcv-qualificationが異なり、後者は異なるため、後者の方が適しています。constこれは、を削除すると、あいまいなオーバーロードエラーが発生する理由でもあります。つまり、オーバーロードはまったく同じになります。

Ad Update1​​gccはC++0x機能の多くをサポートしています。ネイティブウィンドウはmingwからビルドするか、 cygwinを使用できます。

Ad Update2:右辺値と左辺値に別々のオーバーロードが本当に必要な場合は、それが唯一のオプションのようです。しかし、ほとんどのテンプレートは、任意の種類の参照で正しいことを行います。おそらく、std::forward右辺値と左辺値のどちらを取得したかに応じて、呼び出す関数の適切な解決を保証するために使用します。

于 2011-02-18T07:53:20.987 に答える
3

static_assertただし、修正しても発砲の問題は解決しません。static_assert(false, ...)は、定義時にテンプレートを解析するコンパイラーに対して引き続きトリガーされます(ほとんどの場合はトリガーされます)。

彼らは、関数テンプレートのインスタンス化が不正な形式であることに気付くでしょう。そして、標準では、テンプレート自体に対してエラーを発行することが許可されており、ほとんどの場合、そうします。

これを機能させるには、式を依存させる必要があります。これにより、コンパイラーは、テンプレートを解析するときに、常にfalseと評価されることを認識しません。例えば

template<class> struct false_ { static bool const value = false; };

template<class T>
T f(T &&r)
{
    static_assert(false_<T>::value, "no way"); //< line # 10
    return r;
}
于 2011-02-26T09:16:37.100 に答える