Частичная специализация шаблонов для нескольких типов - PullRequest
0 голосов
/ 25 декабря 2010

В следующем коде я хочу рассмотреть функции (Op s), которые имеют void return вместо которых будут рассматриваться как возвращающие true.Тип Retval и возвращаемое значение Op всегда совпадают.Я не могу различить, используя признаки типа, показанные здесь, и попытки создать частичную специализацию шаблона на основе Retval потерпели неудачу из-за присутствия других переменных шаблона, Op и Args.

Как я могу специализировать только некоторые переменные в специализации шаблона, не получая ошибок?Есть ли другой способ изменить поведение в зависимости от типа возвращаемого значения Op?

template <typename Retval, typename Op, typename... Args>
Retval single_op_wrapper(
        Retval const failval,
        char const *const opname,
        Op const op,
        Cpfs &cpfs,
        Args... args) {
    try {
        CallContext callctx(cpfs, opname);
        Retval retval;
        if (std::is_same<bool, Retval>::value) {
            (callctx.*op)(args...);
            retval = true;
        } else {
            retval = (callctx.*op)(args...);
        }
        assert(retval != failval);
        callctx.commit(cpfs);
        return retval;
    } catch (CpfsError const &exc) {
        cpfs_errno_set(exc.fserrno);
        LOGF(Info, "Failed with %s", cpfs_errno_str(exc.fserrno));
    }
    return failval;
}

Ответы [ 2 ]

1 голос
/ 25 декабря 2010

Вам нужна явная специализация, а не частичная.

template <typename Retval, typename Op, typename... Args>
Retval single_op_wrapper(
        Retval const failval,
        char const *const opname,
        Op const op,
        Cpfs &cpfs,
        Args... args) {
    try {
        CallContext callctx(cpfs, opname);
        Retval retval;
        if (std::is_same<bool, Retval>::value) {
            (callctx.*op)(args...);
            retval = true;
        } else {
            retval = (callctx.*op)(args...);
        }
        assert(retval != failval);
        callctx.commit(cpfs);
        return retval;
    } catch (CpfsError const &exc) {
        cpfs_errno_set(exc.fserrno);
        LOGF(Info, "Failed with %s", cpfs_errno_str(exc.fserrno));
    }
    return failval;
}
template<typename Op, typename... Args> void single_op_wrapper<void, Op, Args>(...) {
    ...
}

Редактировать: Забыл, что вы пишете функцию, а не класс.

0 голосов
/ 25 декабря 2010

Шаблонные функции не могут быть частично специализированными. Есть несколько вещей, которые вы можете сделать: вы можете обернуть функцию в шаблон класса с помощью одного статического метода и специализировать шаблон класса, или вы можете использовать SFINAE, чтобы выбрать лучший выбор функции среди различных функций шаблона:

template <typename O, typename Args...>
void single_op_wrapper( /* all but failval */ ) { // [+]
   // implementation for void
}
template <typename R, typename O, typename Args...>
typename boost::enable_if< boost::is_same<R,bool>, bool >::type // bool if condition is met
single_op_wrapper( /* all args */ ) {
   // implementation for R being a bool
}
template <typename R, typename O, typename Args...>
typename boost::enable_if< boost::is_same<R,char> >::type // by default bool
single_op_wrapper( /* all args */ ) {
   // implementation for void return
} 
template <typename R, typename O, typename Args...>
typename boost::disable_if_c<    boost::is_same<R,char>::value //[*] 
                              || boost::is_same<R,bool>::value
                              , R >::type
single_op_wrapper( /* all args */ ) {
   // implementation when R is neither bool nor void
}

На отдельном шаблоне для void [+]:

В C ++ вы не можете иметь функцию, которая принимает аргумент типа void. Это означает, что вы не можете использовать те же аргументы для случая void, что и для остальных.

На стороне метапрограммирования:

Здесь есть пара хитрых битов ... enable_if - это метафункция, которая определяет внутренний тип, если выполняется условие или ничего иного. Когда компилятор пытается заменить типы в шаблоне, возвращаемый тип будет действительным (и, как таковая, функция будет кандидатом), только если условие выполнено. Метафункция disable_if имеет противоположное поведение. Прямой вариант enable_if / disable_if принимает метафункцию в качестве первого аргумента и, необязательно, тип в качестве второго аргумента. Вторая версия enable_if_c / disable_if_c принимает логическое значение в качестве первого аргумента.

В [*] важно отметить, что функции должны быть эксклюзивными. То есть, если для данного типа более одного из шаблонов являются кандидатами, так как ни один из них не является специализацией других, компилятор остановится с ошибкой неоднозначности. Вот причина использования disable_if в последнем шаблоне.

Примечание: я использовал boost пространство имен вместо std, так как я никогда не играл с метапрограммированием в c ++ 0x, но я считаю, что вы можете изменить boost пространство имен с std в вашем компиляторе , Проверьте документы заранее!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...