使用带可变参数模板函数的decltype的尾随返回类型 [英] trailing return type using decltype with a variadic template function

查看:265
本文介绍了使用带可变参数模板函数的decltype的尾随返回类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一个简单的加法器(用于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;
}

在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);

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

解决方案

我认为问题是,可变函数模板只有在返回类型,使 decltype 中的 sum 永远不能引用可变参数模板本身。但我不知道这是一个GCC错误或C ++ 0x根本不允许这样。我的猜测是C ++ 0x不允许在 - > decltype(expr)部分中的递归作为一种解决方法,我们可以避免在 - > decltype(expr)中使用自定义traits类进行这种递归调用:

  #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 ...& {};这样,我们可以用 decltype 替换


$ b你的程序与 typename sum_type< T,P ...> :: type ,它会编译。



Edit:由于这实际上会返回 decltype((a + b)+ c) 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>()
) {};


I want to write a simple adder (for giggles) that adds up every argument and returns a sum with appropriate type. Currently, I've got this:

#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;
}

On GCC 4.5.1 this seems to work just fine for 2 arguments e.g. sum(2, 5.5) returns with 7.5. However, with more arguments than this, I get errors that sum() is simply not defined yet. If I declare sum() like this however:

template <class T, class P...>
T sum(const T& t, const P&... p);

Then it works for any number of arguments, but sum(2, 5.5) would return integer 7, which is not what I would expect. With more than two arguments I assume that decltype() would have to do some sort of recursion to be able to deduce the type of t + sum(p...). Is this legal C++0x? or does decltype() only work with non-variadic declarations? If that is the case, how would you write such a function?

解决方案

I think the problem is that the variadic function template is only considered declared after you specified its return type so that sum in decltype can never refer to the variadic function template itself. But I'm not sure whether this is a GCC bug or C++0x simply doesn't allow this. My guess is that C++0x doesn't allow a "recursive" call in the ->decltype(expr) part.

As a workaround we can avoid this "recursive" call in ->decltype(expr) with a custom traits class:

#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... > {};

This way, we can replace decltype in your program with typename sum_type<T,P...>::type and it will compile.

Edit: Since this actually returns decltype((a+b)+c) instead of decltype(a+(b+c)) which would be closer to how you use addition, you could replace the last specialization with this:

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

这篇关于使用带可变参数模板函数的decltype的尾随返回类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆