使用具有可变参数模板函数的decltype的尾随返回类型

Mai*_*ter 38 c++ templates variadic-functions decltype c++11

我想写一个简单的加法器(giggles),它将每个参数相加并返回一个具有适当类型的和.目前,我有这个:

#include <iostream>
using namespace std;

template <class T>
T sum(const T& in)
{
   return in;
}

template <class T, class... P>
auto sum(const T& t, const P&... p) -> decltype(t + sum(p...))
{
   return t + sum(p...);
}

int main()
{
   cout << sum(5, 10.0, 22.2) << endl;
}
Run Code Online (Sandbox Code Playgroud)

在GCC 4.5.1上,这似乎适用于2个参数,例如sum(2,5.5)返回7.5.但是,由于参数多于此,我得到的错误是sum()尚未定义.如果我这样声明sum():

template <class T, class P...>
T sum(const T& t, const P&... p);
Run Code Online (Sandbox Code Playgroud)

然后它适用于任意数量的参数,但sum(2,5.5)将返回整数7,这不是我所期望的.有两个以上的参数我假设decltype()必须进行某种递归才能推导出t + sum(p ...)的类型.这是合法的C++ 0x吗?或者decltype()仅适用于非可变参数声明吗?如果是这样的话,你会怎么写这样的功能?

sel*_*tze 24

我认为问题是可变参数函数模板仅您指定其返回类型后才被视为声明,因此sumin in decltype永远不会引用可变参数函数模板本身.但我不确定这是否是GCC错误或C++ 0x根本不允许这样做.我的猜测是C++ 0x不允许在->decltype(expr)部分中进行"递归"调用.

作为一种解决方法,我们可以避免->decltype(expr)使用自定义特征类进行"递归"调用:

#include <iostream>
#include <type_traits>
using namespace std;

template<class T> typename std::add_rvalue_reference<T>::type val();

template<class T> struct id{typedef T type;};

template<class T, class... P> struct sum_type;
template<class T> struct sum_type<T> : id<T> {};
template<class T, class U, class... P> struct sum_type<T,U,P...>
: sum_type< decltype( val<const T&>() + val<const U&>() ), P... > {};
Run Code Online (Sandbox Code Playgroud)

这样,我们可以decltype在您的程序中替换typename sum_type<T,P...>::type它,它将编译.

编辑:因为这实际上返回decltype((a+b)+c)而不是decltype(a+(b+c))更接近你如何使用添加,你可以用这个替换最后一个特化:

template<class T, class U, class... P> struct sum_type<T,U,P...>
: id<decltype(
      val<T>()
    + val<typename sum_type<U,P...>::type>()
)>{};
Run Code Online (Sandbox Code Playgroud)

  • 是不是'decltype`实际上意味着要取代像这样的非自然结构?我真的希望它只是一个GCC错误,虽然我使用的是4.5.3并且它仍然存在. (3认同)
  • 我已经在 Tomaka17 的解决方案中发表了评论,我认为您的解决方案存在同样的问题,将 `decltype( val&lt;const T&amp;&gt;() + val&lt;const U&amp;&gt;() )` 替换为 `decltype( std::declval&lt;T&gt;( ) + std::declval&lt;U&gt;() )` 应该可以解决问题 (2认同)

Gin*_*lus 9

C++ 14的解决方案:

template <class T, class... P>
auto sum(const T& t, const P&... p){
    return t + sum(p...);
}
Run Code Online (Sandbox Code Playgroud)

返回类型会自动扣除.

在在线编译器中查看


Tom*_*a17 8

显然你不能以递归的方式使用decltype(至少目前,也许他们会修复它)

您可以使用模板结构来确定总和的类型

它看起来很丑,但它确实有效

#include <iostream>
using namespace std;


template<typename... T>
struct TypeOfSum;

template<typename T>
struct TypeOfSum<T> {
    typedef T       type;
};

template<typename T, typename... P>
struct TypeOfSum<T,P...> {
    typedef decltype(T() + typename TypeOfSum<P...>::type())        type;
};



template <class T>
T sum(const T& in)
{
   return in;
}

template <class T, class... P>
typename TypeOfSum<T,P...>::type sum(const T& t, const P&... p)
{
   return t + sum(p...);
}

int main()
{
   cout << sum(5, 10.0, 22.2) << endl;
}
Run Code Online (Sandbox Code Playgroud)