【问题标题】:C++ function template: Derived and explicit return typeC++ 函数模板:派生和显式返回类型
【发布时间】:2014-09-17 11:05:03
【问题描述】:

我有以下问题,我只是没有找到合适的解决方案(也许没有):我有一个模板化方法,其中返回类型取决于输入类型,感谢 C++11 decltype 返回类型可以轻松派生,但是如果需要,我还希望允许用户显式定义返回类型。

更正式地说,我有一个模板化函数f,我希望可以调用它为f(x),既没有明确定义输入也没有明确定义返回类型。而且我还希望能够将其称为 f<ret_t>x() 并明确定义返回类型,但输入类型仍然自动派生。

现在,用 C++11 满足第一个约束很容易(假设还有另一个模板化方法:

template<typename InT>
auto f(const InT& in) -> decltype(/* code deriving the return type using in */);

但这将不允许覆盖返回类型,因为我必须将其添加为第二个模板参数并将decltype派生移动到模板定义中,并且可能需要使用std::declval&lt;InT&gt;std::result_of

template<
    typename InT,
    typename RetT = /* code deriving return type using InT and declval/result_of */>
RetT f(const InT& in);

但是,这样我在调用f 时也总是需要显式定义InT。因此f 的声明以便能够使InT 保持打开状态但指定RetT 应该是:

template<
    typename RetT = /* code deriving return type using InT and declval/result_of */,
    typename InT>
RetT f(const InT& in);

但由于在我需要为RetT 指定默认值时,InT 尚不可用,因此无法使用。

到目前为止我能想到的最好的解决方法,这不是很令人满意,而且似乎也不管用,因为推断 RetT 失败(显然是因为你不能从默认参数中推断出类型) , 是:

template<typename RetT, typename InT>
RetT f(
    const InT& in,
    const RetT& = std::declval</* code deriving return type using InT or in and declval/result_of */>());

有没有更好的方法来为RetT 设置一个依赖于InT 的默认值,同时仍然能够在需要时显式指定RetT?需要注意的是,返回类型需要在函数实现中可用,这样RetT 的对象才能直接在方法体中分配一次。

【问题讨论】:

  • 最后一行在两种情况下被破坏:你不能使用 declval 并且你不能从默认参数中推断出来。
  • @Niall:是的,result_of 可能会起作用。但问题在于这种情况下的论点顺序。
  • 只写两个重载:template &lt;typename IntT&gt; f(InT) -&gt; decltype(...)template &lt;typename R, typename InT&gt; R f(InT)
  • @K-ballo 编译器会在R == InT 时产生不明确的调用错误。
  • @K-ballo 那只是因为你很少有一个函子返回它自己类型的东西。给定struct foo { foo operator()() const { return *this; } };std::bind&lt;foo&gt;(foo()); 是模棱两可的。

标签: c++ templates c++11


【解决方案1】:

您可以使用std::conditionaldummy 类型来检查函数是否具有自动推导类型或用户选择类型。

如果用户明确选择返回类型,则返回类型将不同于dummy 类型,这将是函数的返回类型。否则只需像以前一样使用推导的类型。

以下使用示例:

#include <typeindex>
#include <type_traits>
#include <iostream>

struct dummy
{
};

template<typename RetType = dummy, typename T>
auto f(const T& in)
-> typename std::conditional<std::is_same<RetType, dummy>::value, T, RetType>::type
{
    std::cout<<typeid(RetType).name()<<" "<<typeid(T).name()<<std::endl;
    return in;
}

int main()
{
    f(1);
    f<float>(1);
}

【讨论】:

  • 可能甚至不需要使用dummy - void 可能就足够了。
  • @T.C.如果用户选择 void 作为返回类型,将使用自动推导的类型。我不认为这是需要的
  • 非默认模板参数之前的默认模板参数...我不知道这一点。这很酷。
  • @Felics 选择void 作为返回类型没有多大意义,尤其是考虑到“RetT 的对象将直接在方法体中分配一次,并且只在方法体中分配一次”问题。
  • @T.C.是的,这是真的。并且如果函数返回任何对象 void 不是有效的返回类型。
猜你喜欢
  • 2018-06-06
  • 2018-10-16
  • 2015-06-12
  • 1970-01-01
  • 2020-11-05
  • 1970-01-01
  • 1970-01-01
  • 2015-07-20
  • 2018-04-06
相关资源
最近更新 更多