Метод шаблона 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() {
    // ....
}

Я хочу иметь специализацию в методе-члене в зависимости от типа Ret.

У кого-нибудь есть идеи?


person Philipp H.    schedule 17.08.2012    source источник


Ответы (2)


SFINAE не работает с нешаблонными функциями (членами или не членами).

Как указывает Керрек С.Б., создание шаблонов функций, не являющихся членами, будет работать. Или, как указывает 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;
}
person TemplateRex    schedule 17.08.2012
comment
Вы можете, если одна из перегрузок является единственной жизнеспособной во время вызова. :) liveworkspace.org/code/fd6e5383610d4e0d8fb17c5497991355 - person Xeo; 17.08.2012
comment
@Potatoswatter: На самом деле нет, это была не шутка. См. ссылку, вы можете прекрасно иметь функцию с точно такой же сигнатурой, где только возвращаемый тип решает, жизнеспособна ли она. :P Кроме того, просто используйте std::is_void<Ret>(), признаки типа должны быть получены либо из std::true_type, либо из std::false_type. - person Xeo; 17.08.2012
comment
@Xeo, вы должны опубликовать это как ответ. - person TemplateRex; 17.08.2012
comment
Нет, мне больше нравится диспетчеризация тегов. - person Xeo; 17.08.2012
comment
@Xeo О, я думал, вы имели в виду, что SFINAE работает для нешаблонных функций, если только одна из них жизнеспособна, шутка в том, что это больше не SFINAE, а просто выглядит так. - person Potatoswatter; 17.08.2012

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>(); }
};
person Kerrek SB    schedule 17.08.2012
comment
template<class Rx = Ret> для функций-членов см. мой комментарий к ответу rhalbersma. - person Xeo; 17.08.2012
comment
@Xeo: Вы имеете в виду, что это избавит нас от необходимости писать <T>? Конечно, почему бы и нет :-) - person Kerrek SB; 17.08.2012