2

与えられた:

class Hokey
{
public:
    explicit C(int i): i_(i) { }

    template<typename T>
    T& render(T& t) { t = static_cast<T>(i_); return t; }
private:
    unsigned i_;
};

私が試してみると:

Hokey h(1);
string s;
h.render(s);

コードパッドは静的キャストでエラーを出します:

t.cpp: In member function 'T& Hokey::render(T&) [with T = std::string]':
t.cpp:21:   instantiated from here
Line 11: error: no matching function for call to 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(unsigned int&)'

Hokey::render一致するものはないと言うべきようです。

もちろん、有効なオーバーロードを指定すれば、すべてが機能します。しかし、以下のコードを考えると、行のコメントを外すと、codepad が再びチョークします。

string& render(string& s) const {
    ostringstream out;
    out << i_;
//  s = out.str();
    return s;
}

SFINAEは、最初のケースでは、render 内の問題はエラーではなく、動作する render がないことがエラーであるべきだと言っているのではありませんか?

4

1 に答える 1

7

過負荷解決中のエラーだけではありません。つまり、呼び出しが確実に機能しないことが確実になるまで、エラーの発生を延期します。それ以降はエラーです。

struct example
{
    template <typename T>
    static void pass_test(typename T::inner_type); // A

    template <typename T>
    static void pass_test(T); // B

    template <typename T>
    static void fail_test(typename T::inner_type); // C
};

int main()
{
    // enumerates all the possible functions to call: A and B
    // tries A, fails with error; error withheld to try others
    // tries B, works without error; previous error ignored
    example::pass_test(5);

    // enumerates all the possible functions to call: C
    // tries C, fails with error; error withheld to try others
    // no other functions to try, call failed: emit error
    example::fail_test(5);
}

また、オーバーロードの解決 (したがって SFINAE)は、定義ではなく、関数のシグネチャのみを参照することに注意してください。したがって、これは常に失敗します。

struct example_two
{
    template <typename T>
    static int fail_test(T x)
    {
        return static_cast<int>(x);
    }

    template <typename T>
    static int fail_test(T x)
    {
        return boost::lexical_cast<int>(x);
    }
};

int main()
{
    example_two::fail_test("string");
}

どちらのテンプレート置換でもエラーは発生しません — 関数シグネチャについて — したがって、最初の関数は失敗し、2 番目の関数は失敗しないことがわかっていても、両方の関数を呼び出しても問題ありません。そのため、あいまいな関数呼び出しエラーが発生します。

関数を明示的に有効または無効にすることができますboost::enable_if(またはstd::enable_ifC++0x では と同等boost::enable_if_c)。たとえば、前の例を次のように修正できます。

struct example_two_fixed
{
    template <typename T>
    static boost::enable_if<boost::is_convertible<T, int>, int>
        pass_test(T x) // AA
    {
        return static_cast<int>(x);
    }

    template <typename T>
    static boost::disable_if<boost::is_convertible<T, int>, int>
        pass_test(T x) // BB
    {
        return boost::lexical_cast<float>(x);
    }
};

struct empty {} no_conversion;

int main()
{
    // okay, BB fails with SFINAE error because of disable_if, does AA
    example_two::pass_test(5);

    // okay, AA fails with SFINAE error because of enable_if, does BB
    example_two::pass_test("string");

    // error, AA fails with SFINAE, does BB, fails because cannot lexical_cast
    example_two::pass_test(no_conversion);
}
于 2011-07-27T19:33:39.133 に答える