テンプレートメンバ関数は、使用される場合にのみ生成されることを理解しています。これは、すべての使用された型がそのような関数をサポートしていない場合に便利です。しかし、これは後続の戻り型指定を持つ関数では機能していないようです。以下は、小さな実験です:未使用の場合でもエラーを返す末尾の戻り値型を持つテンプレートメンバ関数
// helper function for case A workaround
template <typename A, typename T>
auto F(T&& x)
-> decltype(x.template f <A>())
{ return x.template f <A>(); }
// helper function for case B workaround
template <typename A, typename T>
auto G(T&& x)
-> decltype(x.g())
{ return x.g(); }
template <typename T>
struct S
{
// case A: not ok in GCC + Clang
template <typename A>
auto f1()
-> decltype(T().template f <A>())
{ return T().template f <A>(); }
// case A workaround: ok in Clang + GCC
template <typename A>
auto f2()
-> decltype(F <A>(T()))
{ return F <A>(T()); }
// case B: ok in GCC, not ok in Clang
template <typename A>
auto g1()
-> decltype(T().g())
{ return T().g(); }
// case B workaround: ok in GCC + Clang
template <typename A>
auto g2()
-> decltype(G <A>(T()))
{ return G <A>(T()); }
};
このサンプルは、唯一の問題を説明することを意味し、それは何か他のものに有用ではないことを心に留めておいてください。
S <T>
は、適切なメンバー関数f
,g
を持つ任意のタイプT
でインスタンス化できます。
ただし、S <int>
をインスタンス化しようとすると、 S <int> s{};
によって、type 'int' is not a structure or union
のようなエラーが表示されます。これは、タイプT
(この場合はint
)の値に対してそれぞれf1
,g1
のテンプレート関数f
またはテンプレート以外の関数g
を呼び出す場合に発生します。オブジェクトs
にf1
またはg1
を呼び出そうとしていないにもかかわらず、それが起こります。しかし、GCCはg1
の場合は問題ありません。 Clangはそうではありません。
ケースA(テンプレートメンバー関数f
)の回避策は、F
というヘルパー関数を使用することです。これはf2
であり、ClangとGCCの両方でうまく機能します。呼び出しT().template f <A>()
がf2
の宣言から隠されており、A
が不明の場合、コンパイラはF <A>(T())
を探していないため、動作するようです。
ケースB(非テンプレートメンバー関数g
)の同じ回避策も両方のコンパイラで機能しています。
私は何が起こっているのか調べるのに助けていただきたいと思います。いずれの場合も正しい行動はどれですか?どのコンパイラが正しいのですか?一般的に回避策がありますか?
私はGCC 4.8.1とClang 3.3を使用しています。
ないあなたの質問への答えが、 ' F x.templateです() '法的なC++文ですか? 'x.f 'でなければならない。()' – Gasim
@Gasim醜いかもしれないが、残念ながら 'template'キーワードが必要です。例えば、 'f'はデータメンバーかもしれないので、' x.f iavr
['std :: enable_if'](http://en.cppreference.com/w/cpp/types/enable_if)について知っていますか? – Constructor