关于c ++:使用SFINAE根据函数的特定重载是否存在来选择函数

Using SFINAE to select function based on whether a particular overload of a function exists

本问题已经有最佳答案,请猛点这里访问。

我一直在尝试根据是否存在重载operator<<(std::ostream&, const T&),在两个模板化函数之间进行选择。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <typename T, typename std::enable_if</* ? */, int>::type = 0>
std::string stringify(const T& t)
{
    std::stringstream ss;
    ss << t;
    return ss.str();
}

template <typename T, typename std::enable_if</* ? */, int>::type = 0>
std::string stringify(const T& t)
{
    return"No overload of operator<<";
}

struct Foo { };

int main()
{
    std::cout << stringify(11) << std::endl;
    std::cout << stringify(Foo{}) << std::endl;
}

这有可能吗?如果是这样,你将如何解决这个问题?


不需要使用enable_if,当存在operator<<时,使用表达式sfinae来选择正确的重载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace detail
{
    template<typename T>
    auto stringify(std::stringstream& ss, T const& t, bool)
        -> decltype(ss << t, void(), std::string{})
    {
        ss << t;
        return ss.str();
    }

    template<typename T>
    auto stringify(std::stringstream&, T const&, int)
        -> std::string
    {
        return"No overload of operator<<";
    }
}

template <typename T>
std::string stringify(const T& t)
{
    std::stringstream ss;
    return detail::stringify(ss, t, true);
}

现场演示

stringify函数模板简单地委托给detail::stringify函数模板之一。然后,如果表达式ss << t格式正确,则选择第一个表达式。未命名的bool参数用于消除两个detail::stringify实现之间的歧义。由于主stringify函数通过true作为detail::stringify的参数,因此当operator<<过载时,第一个函数将是更好的匹配。否则将选择第二个。

第一个stringify模板的尾随返回类型中的表达式decltype(ss << t, void(), std::string{})可能需要更详细的解释。这里我们有一个单独的表达式,由3个子表达式组成,用逗号运算符分隔。

第一个是ss << t,它决定函数模板是否通过模板参数替换,并将添加到重载解决方案集。如果表达式格式正确,即如果所讨论的类型重载operator<<,则会发生这种情况。

中间的子表达式void()除了确保不选择某些用户定义的operator,(因为不能用void参数类型重载operator,)。

第三个也是最右边的子表达式std::string{}决定了detail::stringify函数的返回类型。