9

std::forward_listオブジェクトに実際にアクセスする必要がない可能性のある提供insert_afterおよびメンバー。したがって、それらはメンバー関数として実装され、リスト オブジェクトなしで呼び出すことができます。これは、非常に一般的な用途である、リストから自分自身を削除したいオブジェクトに役立ちます。EDIT : この最適化は、特殊化またはユーザー定義のステートレス アロケーターにのみ適用されます。erase_afterstd::forward_liststaticforward_liststd::allocator

標準準拠の実装でこれを行うことができますか?

§17.6.5.5/3 は言う

C++ 標準ライブラリで記述されているメンバー関数シグネチャの呼び出しは、実装が追加のメンバー関数シグネチャを宣言していないかのように動作します。

脚注付き

有効な C++ プログラムは、期待されるライブラリ メンバー関数、または同等の動作をする関数を常に呼び出します。実装では、有効な C++ プログラムによって呼び出されない追加のメンバー関数を定義することもできます。

追加staticすると「異なる」メンバー関数が作成されるかどうかは明確ではありませんが、(暗黙の) 引数を削除しても、デフォルトの引数を追加しても壊れないものは壊れません。これは合法です。(標準メンバー関数に PTMF を合法的に使用することはできません。)

図書館がこれを行うことを許可されるべきだと思いますが、何らかの規則が破られるかどうかはわかりません。また、列挙されたメンバー関数のプロトタイプはどの程度規範的ですか?

4

1 に答える 1

9

標準では、誰も違いがわからない場合は問題なく使用できるとされています。そして、合法的に PTMF を に作成できないことは正しいforward_listので、そうすれば安全です。

カスタム アロケータの危険性はすでに指摘されています。しかし、誰かが特殊化して、が呼び出されていないことを検出するstd::allocator<T>危険性があります。std::allocator<MyType>allocator::construct/destroy

わかりましたが、特殊化してstd::forward_list<int>(カスタム アロケータなし、ユーザー定義の value_type なし)、insert_after静的にすることはできますか?

いいえ。この変更は、新しい SFINAE 機能で検出できます。ここにデモがあります:

#include <memory>
#include <iostream>

template <class T, class A = std::allocator<T>>
class forward_list
{
public:
    typedef T value_type;
    struct const_iterator {};
    struct iterator {};

    iterator insert_after(const_iterator p, const T& x);
};

template <class C>
auto test(C& c, typename C::const_iterator p, const typename C::value_type& x)
    -> decltype(C::insert_after(p, x))
{
    std::cout << "static\n";
    return typename C::iterator();
}

template <class C>
auto test(C& c, typename C::const_iterator p, const typename C::value_type& x)
    -> decltype(c.insert_after(p, x))
{
    std::cout << "not static\n";
    return typename C::iterator();
}

int main()
{
    ::forward_list<int> c;
    test(c, ::forward_list<int>::const_iterator(), 0);
}

このプログラムが実行され、出力されます。

not static

しかし、insert_after静的にすると:

static iterator insert_after(const_iterator p, const T& x);

次に、コンパイル時エラーが発生します。

test.cpp:34:5: error: call to 'test' is ambiguous
    test(c, ::forward_list<int>::const_iterator(), 0);
    ^~~~
test.cpp:16:6: note: candidate function [with C = forward_list<int, std::__1::allocator<int> >]
auto test(C& c, typename C::const_iterator p, const typename C::value_type& x)
     ^
test.cpp:24:6: note: candidate function [with C = forward_list<int, std::__1::allocator<int> >]
auto test(C& c, typename C::const_iterator p, const typename C::value_type& x)
     ^
1 error generated.

違いが検出されました。

forward_list::insert_afterしたがって、静的にすることは不適合です。

アップデート

「静的」オーバーロードを呼び出し可能にしたい場合は、単に「非静的」オーバーロードよりも望ましいものにする必要があります。これを行う 1 つの方法は、「非静的」オーバーロードを次のように変更することです。

template <class C, class ...Args>
auto test(C& c, typename C::const_iterator p, const typename C::value_type& x, Args...)
    -> decltype(c.insert_after(p, x))
{
    std::cout << "not static\n";
    return typename C::iterator();
}

insert_afterこれで、メンバー関数が静的かどうかに応じて、テストは「静的」または「静的ではない」のいずれかを出力します。

于 2011-10-19T16:51:56.330 に答える