C++ 模板方法启用\u if专门化

C++ 模板方法启用\u if专门化,c++,class,templates,c++11,enable-if,C++,Class,Templates,C++11,Enable If,我有以下不编译的代码。 这是接受参数的模板类中的两个函数 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() { // .... } typenam

我有以下不编译的代码。 这是接受参数的模板类中的两个函数

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() {
    // ....
}
typename std::enable_if::type_on_dispatched(){
// ...
}
typename std::enable_if::value,Ret>::type_on_dispatched(){
// ....
}
我希望根据Ret的类型对成员方法进行专门化


有人知道吗?

SFINAE不支持非模板函数(成员或非成员)

正如Kerrek SB所指出的,让它们成为非成员函数模板是可行的。或者正如Xeo所指出的,使用默认的模板参数使它们成为成员函数模板也会起作用

但是,这只是因为两个
std::enable_(如果
条件不重叠)才起作用。如果您想为
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;
}
#包括
模板
福班
{
公众:
void_on_dispatched()
{
//标记分发:创建std::false\u类型或std::true\u类型的虚拟对象
//几乎可以保证由一个像样的编译器进行优化
helper_on_已调度(std::is_void());
} 
私人:
已调度上的无效帮助程序(std::false\u类型)
{
//为非空而做事
}
已调度的\u上的void helper\u(std::true\u类型)
{
//虚度光阴
}
};
int main()
{
Foo()._on_dispatched();
Foo()._on_dispatched();
返回0;
}

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() { /*...*/ }
模板
typename std::enable_if::type_on_dispatched(){/*…*/}
模板
typename std::enable_if::value,Ret>::type_on_dispatched(){/*…*/}
用法:

auto q = _on_dispatched<int>();
auto q=_on_dispatched();
当然,您不能推断函数的返回类型,因为它是不可推断的。但是,您可以将此模板打包到另一个模板中:

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

    T bar() { return _on_dispatched<T>(); }
};
模板
结构Foo
{
//在这里插入模板,也许如此
T bar(){return_on_dispatched();}
};

如果其中一个重载是调用时唯一可行的重载,则您可以:@波塔托斯瓦特:事实上,不,这不是一个玩笑。请参阅链接,您完全可以拥有一个具有完全相同签名的函数,其中只有返回类型决定它是否可行P同样,只需使用
std::is_void()
,类型特征需要从
std::true_type
std::false_type
派生。顺便说一句,@Xeo您应该将此作为答案发布。不,我更喜欢标记调度。
模板
用于成员函数,请看我对拉尔伯斯玛答案的评论。@Xeo:你的意思是这样我们就不用写
?当然,为什么不:-)