【问题标题】:Specializing return type for a variadic template可变参数模板的特殊返回类型
【发布时间】:2013-05-31 15:39:18
【问题描述】:

首先,如果我在英语方面犯了大错误,我很抱歉,我是法国人,但我会尽力写得最好!好吧,我正在努力使用 C++11 可变参数模板。我想做一些有点棘手的事情。

确实,我想专门化我的模板的返回类型,知道它是一个可变参数模板。

我的目标是实现以下目标:

l.callFun<int>("addition", 40, 1, 1);

特化对应于用户想要的返回类型。它是一个 Lua 绑定,所以如果用户不精确,我无法确定返回类型(显然,如果没有专门化,默认值将是 void 返回)。后来,是在 Lua 中调用的函数的名称。然后,这 3 个整数对应于我的可变参数模板。

现在,我的模板如下所示:

template <typename Z, typename T, typename... U>
Z LuaScript::callFun(const std::string& name, const T& head, const U&... tail);

但我似乎无法对模板函数进行部分特化。有没有人可以帮助我?

非常感谢!

【问题讨论】:

  • 那么你想写的偏特化是什么?您可以在调用时部分指定模板参数,但这是另一回事。
  • 我要专精的是返回类型!
  • 我认为你的意思是你想参数化返回类型;)。在我的回答中,我包含了一篇关于部分专业化的文章的链接,以防您想了解更多信息。

标签: c++ templates c++11 specialization variadic


【解决方案1】:

非常感谢 pheedbaq 的帮助和文档,但最后,我提出了一个非常简单的解决方案。我没有那样做,所以多亏了你,我将尝试这种运算符重载的方式;)

我所做的是打包可变参数,并调用另一个模板来专门处理返回类型。所以我有类似的东西:

template <typename Z, typename... T>
Z LuaScript::callFun(const std::string& name, const T&... args)
{
    Z ret;
    callFunReal(args);
    [...]
    ret = returnType<Z>();
    return (ret);
}

真的很简单,但是不知道具体怎么做……谢谢大家! :)

【讨论】:

  • 很高兴你知道了 :) 嘿别忘了标记答案,即使是你自己的。这将建立声誉,人们在决定回答问题时会考虑这一点。
  • 是的是的,我知道,只是我要等一天才能将自己的答案标记为答案,我只是在等待:)
  • 大声笑,我明白了。只是为了好玩,我对使用完美转发的代码进行了修改,并允许用户按照您最初描述的方式进行呼叫。
【解决方案2】:

不需要更改界面的解决方案是将函数调用转发到template&lt;&gt; class,您可以在其中专注于您的内心:

template<typename R, typename... Ts>
struct DoCallFun {
  R operator()( LuaScript* self, std::string const& name, Ts&&... ts ) {
  }
};

template <typename Z, typename... T>
Z LuaScript::callFun(const std::string& name, Ts&&... ts) {
  return DoCallFun<Z, Ts...>()( this, name, head, std::forward<Ts>(ts)... )
}

我们在DoCallFun 中实现callFun 的主体。如果它需要访问LuaScript 中的私有变量,我们将DoCallFun 设为friend

现在,更好的解决方案可能是对大部分 return 类型的依赖行为使用“特征 class”。如果您需要基于return 类型调用不同的函数,而不是为每个return 类型编写一次相同的callFun 并略有不同,您可以创建一个“特征class”来隔离基于return 类型的差异。

假设如果类型为int,则需要调用int CallAndReturnInt(...),如果类型为double,则需要调用double CallAndReturnDouble(...)。不要有两个 callFun 的主体,而是编写一个特征类:

template<typename T>
struct lua_return_traits;
template<>
struct lua_return_traits<int> {
  template<typename... Ts>
  static int call_and_return( Ts&&... ts ) {
    return CallAndReturnInt( std::forward<Ts>(ts) );
  }
};
template<>
struct lua_return_traits<double> {
  template<typename... Ts>
  static double call_and_return( Ts&&... ts ) {
    return CallAndReturnDouble( std::forward<Ts>(ts) );
  }
};

根据return 类型,您的方法应该有所不同的其他方式的类似技术。

【讨论】:

    【解决方案3】:

    将初始调用完美地转发给辅助类成员函数应该有助于实现您想要的。

    template<typename Z>
    struct callFun_helper {
        template<typename T, typename... U>
        static Z help(const std::string& name, const T& head, const U&... tail) {
            Z thing;
            //do something with "thing"
            return thing;
        }
    };
    
    template<typename Z, typename S, typename T, typename... U>
    auto callFun(S&& s, T&& t, U&&... u)
    -> decltype(callFun_helper<Z>::help(std::forward<S>(s), std::forward<T>(t), std::forward<U>(u)...)) {
        return callFun_helper<Z>::help(std::forward<S>(s), std::forward<T>(t), std::forward<U>(u)...);
    }
    
    //main
    callFun<string>("addition", 40, 1, 1)    
    

    如果您想了解更多关于您可以/不能用它做什么,下面的链接可能会帮助您进行部分模板专业化。另外,如果您想将来在 StackOverflow 上继续获得答案,请不要忘记标记答案:)

    Why Not Specialize Function Templates?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-13
      • 2022-01-13
      • 2012-11-18
      • 2021-12-17
      • 2011-09-08
      • 1970-01-01
      • 2023-02-05
      • 2023-03-22
      相关资源
      最近更新 更多