使用带有可变参数模板函数的 decltype 的尾随返回类型
我想编写一个简单的加法器(用于傻笑),将每个参数相加并返回具有适当类型的总和.目前,我有这个:
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;
}
在 GCC 4.5.1 上,这似乎适用于 2 个参数,例如sum(2, 5.5) 返回 7.5.但是,有比这更多的参数,我得到 sum() 尚未定义的错误.但是,如果我像这样声明 sum() :
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);
然后它适用于任意数量的参数,但 sum(2, 5.5) 将返回整数 7,这不是我所期望的.有两个以上的参数,我假设 decltype() 必须进行某种递归才能推断出 t + sum(p...) 的类型.这是合法的 C++0x 吗?还是 decltype() 仅适用于非可变参数声明?如果是这样,您将如何编写这样的函数?
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?
推荐答案
我认为问题在于可变参数函数模板仅在您指定其返回类型之后才被考虑声明,以便 sum
永远不能引用可变参数函数模板本身.但我不确定这是 GCC 错误还是 C++0x 根本不允许这样做.我的猜测是 C++0x 不允许在 decltype
中的 ->decltype(expr)
部分进行递归"调用.
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.
作为一种解决方法,我们可以在 ->decltype(expr)
中使用自定义特征类避免这种递归"调用:
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... > {};
这样,我们可以用 typename sum_type
替换你程序中的 decltype
并且它会编译.
This way, we can replace decltype
in your program with typename sum_type<T,P...>::type
and it will compile.
因为这实际上返回 decltype((a+b)+c)
而不是 decltype(a+(b+c))
这将更接近于您如何使用加法,您可以用这个替换最后一个专业化:
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>()
)>{};
相关文章