3

どこかで他の質問に答えて、私はこのコードを書きました。

struct no_type{};
template<typename T> struct has_apply {
    static decltype(T().apply<0u>(double())) func( T* ptr );
    static no_type func( ... );
    static const bool result = !std::is_same<no_type, decltype(func(nullptr))>::value;
};

class A {
public:
    template< unsigned n >
    void apply( const double& );

};
class B {
};

int main()
{
  std::cout << std::boolalpha << has_apply< A >::result << '\n';
  std::cout << std::boolalpha << has_apply< B >::result << '\n';
  std::cin.get();
  return( 0 );
}

Tが、二重右辺値とテンプレートパラメータリテラルを受け入れる非静的メンバー関数 "apply"を提供する場合、結果はtrueである必要があり、それ以外の場合はfalseであるように思われます。ただし、与えられた例は、コンパイル時にクラスBのコンパイルに実際に失敗しますhas_apply<B>。decltypeステートメントでTの置換が失敗したという事実は、それが単に他の関数を呼び出すことを意味するのではないでしょうか?そういうSFINAEのポイントじゃないですか?

これまでで最もばかげた、無意味な方法で解決しました:

struct no_type{};
template<typename T> struct has_apply {
    template<typename U> static decltype(U().apply<0u>(double())) func( U* );
    template<typename U> static no_type func( ... );
    static const bool result = !std::is_same<no_type, decltype(func<T>(nullptr))>::value;
};

class A {
public:
    template< unsigned n >
    void apply( const double& );

};
class B {
};

int main()
{
  std::cout << std::boolalpha << has_apply< A >::result << '\n';
  std::cout << std::boolalpha << has_apply< B >::result << '\n';
  std::cin.get();
  return( 0 );
}
4

1 に答える 1

3

SFINAEは、関数テンプレートのテンプレートパラメータの置換が失敗した場合に適用されます。あなたの場合のように、問題の(非テンプレート)関数をメンバーとして持つクラステンプレートのテンプレートパラメータには適用されません。

それを修正した後、式は依存型であるため、少なくともに変更decltype(T().apply<0u>(double()))する必要があります。その理由はこれです:コンパイラが最初に見たとき、それはまだ何も知らないので、トークンをどのように解析する必要がありますか?メンバーテンプレートである可能性があり、次にその引数リストを開始します。OTOHは、代わりに非テンプレートメンバー(データメンバーなど)である可能性があり、「より小さい」演算子として解析されます。あいまいさがあり、コンパイラがこの時点でそれを解決するにはまだ時期尚早です。プログラマーがコンパイラーに何を伝えるために使用できる曖昧性解消メカニズムが必要です。decltype(T().template apply<0u>(double()))T()T().apply<0u>Tapply<.apply<apply<applyテンプレートであるかどうか。そして、ここに.template(または->template、または::template)構文があります。存在する場合、コンパイラはそれがテンプレートメンバーであるべきであると認識します。そうでない場合、コンパイラはメンバーがテンプレートであってはならないことを認識します。

最後に、私が作成した例を示します。これは正しく機能し、g++4.5.0で目的の結果を生成します-std=c++0x

#include <iostream>

template < class T >
decltype( T().template apply< 0u >( double() ) ) f( T &t )
{
    return t.template apply< 0u >( 5. );
}

const char *f( ... )
{
    return "no apply<>";
}

class A {
public:
    template < unsigned >
    int apply( double d )
    {
        return d + 10.;
    }
};

class B {};

int main()
{
    A a;
    std::cout << f( a ) << std::endl;
    B b;
    std::cout << f( b ) << std::endl;
}

出力は次のとおりです。

15
no apply<>

.templateここで、最初のf()定義から両方を削除すると、出力は次のようになります。

no apply<>
no apply<>

これは、という名前の非テンプレートメンバーclass Aがないため、の置換が失敗したことを示します。SFINAEの動作中!apply

于 2010-11-09T18:26:39.307 に答える