20

const参照、または右辺値の場合は右辺値参照のいずれかによって値を取得するために関数をオーバーロードするのに問題があります。問題は、私の非定数左辺値が関数の右辺値バージョンにバインドされていることです。私はVC2010でこれを行っています。

#include <iostream>
#include <vector>

using namespace std;

template <class T>
void foo(const T& t)
{cout << "void foo(const T&)" << endl;}

template <class T>
void foo(T&& t)
{cout << "void foo(T&&)" << endl;}

int main()
{
    vector<int> x;
    foo(x); // void foo(T&&) ?????
    foo(vector<int>()); // void foo(T&&)
}

優先順位はfoo(x)を次のように推測することのようです

foo< vector<int> & >(vector<int>& && t)

それ以外の

foo< vector<int> >(const vector<int>& t)

右辺値参照バージョンを次のように置き換えてみました

void foo(typename remove_reference<T>::type&& t)

しかし、これはすべてをconst-lvalue参照バージョンに解決させる効果しかありませんでした。

この動作を防ぐにはどうすればよいですか?そして、なぜこれがデフォルトなのか-右辺値参照の変更が許可されていることを考えると非常に危険なようです。これにより、予期せず変更されたローカル変数が残ります。

編集:関数の非テンプレートバージョンを追加しただけで、期待どおりに機能します。関数をテンプレートにすると、過負荷解決ルールが変更されますか?それは..本当にイライラします!

void bar(const vector<int>& t)
{cout << "void bar(const vector<int>&)" << endl;}

void bar(vector<int>&& t)
{cout << "void bar(vector<int>&&)" << endl;}

bar(x); // void bar(const vector<int>&)
bar(vector<int>()); // void bar(vector<int>&&)
4

2 に答える 2

26

このようなテンプレート関数がある場合、オーバーロードすることはほとんどありません。このT&&パラメーターは、catchanythingパラメーターです。また、これを使用して、 1つの過負荷から必要な動作を取得できます。

#include <iostream>
#include <vector>

using namespace std;

template <class T>
void display()
{
    typedef typename remove_reference<T>::type Tr;
    typedef typename remove_cv<Tr>::type Trcv;
    if (is_const<Tr>::value)
        cout << "const ";
    if (is_volatile<Tr>::value)
        cout << "volatile ";
    std::cout << typeid(Trcv).name();
    if (is_lvalue_reference<T>::value)
        std::cout << '&';
    else if (is_rvalue_reference<T>::value)
        std::cout << "&&";
    std::cout << '\n';
}

template <class T>
void foo(T&& t)
{
    display<T>();
}

int main()
{
    vector<int> x;
    vector<int> const cx;
    foo(x); // vector<int>&
    foo(vector<int>()); // vector<int>
    foo(cx);  // const vector<int>&
}
于 2011-10-13T00:55:21.563 に答える
12

T&&左辺値参照にバインドするには、それT自体が左辺値参照型である必要があります。テンプレートが参照型でインスタンス化されるのを禁止できますT

template <typename T>
typename std::enable_if<!std::is_reference<T>::value>::type foo(T&& t)
{
    cout << "void foo(T&&)" << endl;
}

enable_ifにあり<utility>ます; is_referenceにあります<type_traits>

T&&オーバーロードの取得がaのオーバーロードの取得よりも優先される理由は、(との)完全一致ですT const&が、資格変換が必要なためです(const-qualificationを追加する必要があります)。T&&T = vector<int>&T const&

これはテンプレートでのみ発生します。をとる非テンプレート関数がある場合はstd::vector<int>&&、右辺値引数を使用してのみその関数を呼び出すことができます。をとるテンプレートがある場合T&&、それを「右辺値参照パラメーター」と考えるべきではありません。これは「ユニバーサルリファレンスパラメータ」です(Scott Meyersは同様の言語を使用したと思います)。それは何でも受け入れることができます。

関数テンプレートのT&&パラメーターを任意のカテゴリーの引数にバインドできるようにすることで、完全な転送が可能になります。

于 2011-10-13T00:36:19.677 に答える