9

これは、clang 3.3 で問題なくコンパイルされます。

template <typename T>
struct M;

template <typename R, typename C, typename... A>
struct M <R (C::*)(A...)> { };

template <typename R, typename C, typename... A>
struct M <R (C::*)(A...) &> { };

しかし、gcc 4.8.1 では失敗します:

[...] error: redefinition of ‘struct M <R (C::*)(A ...)>’
 struct M <R (C::*)(A...) &> { };
        ^
[...] error: previous definition of ‘struct M <R (C::*)(A ...)>’
 struct M <R (C::*)(A...)> { };
        ^

これをさまざまなコンテキストで使用すると、クラッシュや内部コンパイラ エラーなど、あらゆる種類の予期しないコンパイラの動作が発生します。

ref 修飾されたメンバー関数は、標準では「*this の右辺値参照」( N2439 ) と呼ばれ、gcc 4.8.1 でサポートされていることを理解しています。

ここでの問題は、gcc が ref 修飾されたメンバー関数型と通常のメンバー関数型を区別していないように見えるテンプレート引数としてそれらを使用することです。

clang の std ライブラリの実装は、この機能がサポートされているかどうかを検出するようです。

__has_feature(cxx_reference_qualified_functions)

では、ref 修飾された関数のこの使用は標準ですか、それとも言語拡張ですか?

4

1 に答える 1

3

8.3.5 [dcl.fct] パラグラフ 6 によると (引用されたテキストに強調表示を追加しました):

デフォルトの引数 (8.3.6) や例外仕様 (15.4) ではなく、戻り値の型、 parameter-type-list、ref-qualifier 、および cv-qualifier-seqは関数 type の一部です

つまり、ref 修飾子は確かに型の一部です。さらに、8.4.1 [dcl.fct.def.general] パラグラフ 5 によれば、ref 修飾子を含むメンバーへのポインターを作成できます。

cv-qualifier-seq またはref-qualifier (またはその両方)、非静的メンバー関数宣言、非静的メンバー関数定義、またはメンバー関数へのポインターのみ(8.3.5) の一部にすることができます。9.3.2 を参照。

ref-qualifier を持つメンバー関数へのポインターを型以外のテンプレート引数として使用できないという特定の制限はありません。つまり、使用しようとした部分的な特殊化が機能するはずです。ただし、ref 修飾子のサポートは、clang と gcc の両方でかなり新しい機能です。つまり、すべてのコーナー ケースが解決されたわけではありません。gcc (20130811) と clang (トランク 190769) の両方のかなり最近のスナップショットで上記の抜粋を試してみたところ、どちらもコードを正常にコンパイルできました。もちろん、このスニペットは実際には何もしませんし、私はこの機能を悪用しようとはしませんでした。いくつかのコンパイラのバグを引き起こしただけだと思いますが、両方のプロジェクトが最新のスナップショットに対するエラー レポートを歓迎すると確信しています。

于 2013-09-17T22:08:52.143 に答える