0

在下面的代码中,我想考虑Op具有 return to 的函数(s)void而不是被视为 return true。的类型Retval和返回值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 回答
0

这是我用来绕过 C++ 中函数缺少部分模板特化的技巧。基本上,这依赖于函数重载和多个函数声明之间的灰色区域,由于 SFINAE 规则不会导致编译器错误(所有enable_if_t布尔条件都是互斥的,因此在给定任何特定编译单元上下文的情况下,只有一个声明有效)


template < class T, std::enable_if_t< sizeof(T) == 4, int > = 0 >
T do_transform(T inp) {
  // 4 byte implementation
}


template < class T, std::enable_if_t< sizeof(T) == 8, int > = 0 >
T do_transform(T inp) {
 // 8 byte implementation
}

template <class T, std::enable_if_t< sizeof(T) > 8, int> = 0 >
T do_transform(T inp) {
 // very much wide word types
}

于 2021-07-23T01:18:20.270 回答