【问题标题】:Partial template specialization for more than one typename多个类型名的部分模板特化
【发布时间】:2010-12-25 09:02:33
【问题描述】:

在下面的代码中,我想考虑返回 void 的函数 (Ops),而不是考虑返回 trueRetval 的类型和Op 的返回值总是匹配的。我无法使用此处显示的类型特征进行区分,并且由于其他模板变量 OpArgs 的存在,尝试创建基于 Retval 的部分模板特化失败。

如何在模板特化中只特化一些变量而不会出错?有没有其他方法可以根据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;
}

【问题讨论】:

    标签: c++ templates c++11 return-type template-specialization


    【解决方案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>(...) {
        ...
    }
    

    编辑:忘记你写的是函数,而不是类。

    【讨论】:

      【解决方案2】:

      模板函数不能部分特化。您可以做不同的事情:您可以使用单个静态方法将函数包装到类模板中并专门化类模板,或者您可以使用 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 中使用过元编程,但我相信您可以在编译器中使用 std 更改 boost 命名空间.提前查看文档!

      【讨论】:

        【解决方案3】:

        这是我用来绕过 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
        }
        
        

        【讨论】:

          猜你喜欢
          • 2017-09-20
          • 1970-01-01
          • 1970-01-01
          • 2012-09-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-23
          • 1970-01-01
          相关资源
          最近更新 更多