6

我有以下无法编译的代码。这是模板类中的两个函数,它们接受参数

typename std::enable_if<std::is_void<Ret>::value, Ret>::type _on_dispatched() {
    // ...
}

typename std::enable_if<!std::is_void<Ret>::value, Ret>::type _on_dispatched() {
    // ....
}

我想根据 Ret 的类型对成员方法进行专门化。

有人有什么想法吗?

4

2 回答 2

7

SFINAE 不适用于非模板函数(成员或非成员)。

正如 Kerrek SB 所指出的,使它们成为非成员函数模板将起作用。或者正如 Xeo 指出的那样,使它们具有默认模板参数的成员函数模板也将起作用。

但是,这仅起作用,因为这两个std::enable_if条件不重叠。如果您想为int(比如说)添加不同的重载,那么您会发现它的扩展性不那么好。根据您要执行的操作,标签调度通常比 SFINAE 具有更好的扩展性,您希望在多个备选方案上进行调度:

#include<type_traits>

template<typename Ret>
class Foo
{
public:
    void _on_dispatched()
    {
        // tag dispachting: create dummy of either std::false_type or std::true_type
        // almost guaranteed to be optimized away by a decent compiler
        helper_on_dispatched(std::is_void<Ret>()); 
    } 

private:
    void helper_on_dispatched(std::false_type)
    {
        // do stuff for non-void
    }

    void helper_on_dispatched(std::true_type)
    {
        // do stuff for void
    }
};

int main()
{
    Foo<void>()._on_dispatched();
    Foo<int>()._on_dispatched();
    return 0;
}
于 2012-08-17T08:43:55.930 回答
3

SFINAE 仅适用于模板。只需稍加修改即可编译您的代码:

template <typename Ret>
typename std::enable_if<std::is_void<Ret>::value, Ret>::type _on_dispatched() { /*...*/ }

template <typename Ret>
typename std::enable_if<!std::is_void<Ret>::value, Ret>::type _on_dispatched() { /*...*/ }

用法:

auto q = _on_dispatched<int>();

你当然不能推断出函数的返回类型,因为它是不可推断的。但是,您可以将此模板打包另一个模板中:

template <typename T>
struct Foo
{
    // insert templates here, maybe privately so

    T bar() { return _on_dispatched<T>(); }
};
于 2012-08-17T09:08:38.003 回答