0

次のコードでは、 return をOp持つ関数 (s) をvoidreturn と見なしたいと考えていtrueます。typeRetvalと の戻り値Opは常に一致します。ここに示されている型特性を使用して区別することはできませRetvalん.OpArgs

エラーを発生させずに、テンプレートの特殊化で一部の変数のみを特殊化するにはどうすればよいですか? の戻り値の型に基づいて動作を変更する他の方法はあり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;
}
4

3 に答える 3

1

部分的ではなく、明示的な特殊化が必要です。

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>(...) {
    ...
}

編集:クラスではなく関数を書いていたことを忘れました。

于 2010-12-25T10:26:00.990 に答える
0

Template functions cannot be partially specialized. There are different things that you can do: you can wrap the function into a class template with a single static method and specialize the class template, or you can use SFINAE to select the best choice of function among different template functions:

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
}

On the separate template for void [+]:

In C++ you cannot have a function that takes an argument of type void. That means that you cannot use the same arguments for the void case as you are using for the rest of them.

On the metaprogramming side:

There are a couple of tricky bits here... the enable_if is a metafunction that defines an internal type if the condition is met or nothing otherwise. When the compiler tries to substitute the types in the template, the return type will only be valid (and as such the function be a candidate) if the condition is met. The disable_if metafunction has the opposite behavior. The straight variant enable_if/ disable_if take a metafunction as first argument and optionally a type as second argument. The second version enable_if_c / disable_if_c take a boolean as first argument.

It is important in [*] to note that the functions must be exclusive. That is, if for a given type more than one of the templates are candidates, as none of them is an specialization of the others, the compiler will stop with an ambiguity error. That is the reason for using the disable_if in the last template.

Note: I have used boost namespace instead of std as I have not played ever with metaprogramming in c++0x, but I believe that you can change the boost namespace with std in your compiler. Check the docs in advance!

于 2010-12-25T11:05:31.647 に答える