static_cast 的替换失败不是错误(SFINAE)问题

发布于 2024-11-26 10:35:30 字数 1183 浏览 3 评论 0原文

鉴于:

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);

Codepad 在静态转换上给我一个错误:

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 chokes Again:

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

不会 SFINAE 说 - 在第一种情况下 - 渲染中的问题不应该是错误,而不是缺少有效的渲染应该是错误?

Given:

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_;
};

If I try:

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

Codepad gives me an error on the static cast:

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&)'

It seems like it should say that there is no Hokey::render to match.

Of course, if I supply a valid overload, everything works.
But given the code below, you uncomment the line, codepad chokes again:

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

Doesn't SFINAE say that - in the first case - the problem within render should not be the error, rather the absence of a render that works should be the error?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情泪▽动烟 2024-12-03 10:35:30

这只是在重载解析期间不是错误。换句话说,它会推迟给您一个错误,直到确定该调用肯定无法正常工作为止。之后,这是一个错误。

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");
}

对于函数签名来说,任何一个模板替换都没有错误,因此两个函数都可以调用,即使我们知道第一个函数会失败而第二个函数不会失败。所以这会给你一个不明确的函数调用错误。

您可以使用 boost::enable_if(或 C++0x 中的 std::enable_if,相当于 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);
}

It's only not an error during overload resolution. In other words, it puts off giving you an error until it's sure the call definitely isn't going to work. After that, it's an error.

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);
}

It should also be noted that overload resolution (and therefore SFINAE) only looks at the function signature, not the definition. So this will always fail:

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");
}

There are no errors for either template substitution — for the function signatures — so both functions are okay to call, even though we know the first one will fail and the second won't. So this gives you an ambiguous function call error.

You can explicitly enable or disable functions with boost::enable_if (or std::enable_if in C++0x, equivalent to boost::enable_if_c). For example, you might fix the previous example with:

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文