末尾の戻り値の型は、宣言のポイントの前にオーバーロードを使用するため、元の答えは機能しません。また、戻り値の型を知る前に関数を前方宣言することは不可能です。したがって、ヘルパー構造体が必要です。これが機能する(残念ながら現在は非常に複雑な)バージョンです:
#include <utility>
template <typename...>
struct sum_impl;
/* This is the base case */
template <typename T1, typename T2>
struct sum_impl<T1, T2>
{
typedef decltype(std::declval<const T1&>() + std::declval<const T2&>()) result_type;
static result_type doit(const T1& v1, const T2& v2)
{
return v1 + v2;
}
};
/* And here is the recursive definition for left-associativity */
template <typename T1, typename T2, typename... Ts>
struct sum_impl<T1, T2, Ts...>
{
typedef decltype(std::declval<const T1&>() + std::declval<const T2&>()) step_type;
typedef typename sum_impl<step_type, Ts...>::result_type result_type;
static result_type doit(const T1& v1, const T2& v2, const Ts&... rest)
{
return sum_impl<step_type, Ts...>::doit(v1 + v2, rest...);
}
};
template <typename... Ts>
typename sum_impl<Ts...>::result_type sum(const Ts&... args)
{
return sum_impl<Ts...>::doit(args...);
}
デモ: http://ideone.com/jMwgLz
Named's answer の単純さを保持しているが、関連付けられたままのバージョンを次に示します。
/* not really needed, unless someone wants to call sum with only a single argument */
template <typename T>
T sum(const T& v)
{
return v;
}
/* This is the base case */
template <typename T1, typename T2>
auto sum(const T1& v1, const T2& v2) -> decltype( v1 + v2 )
{
return v1 + v2;
}
/* And here is the recursive definition for left-associativity */
template <typename T1, typename T2, typename... Ts>
auto sum(const T1& v1, const T2& v2, const Ts&... rest) -> decltype( sum(v1 + v2, rest...) )
{
return sum(v1 + v2, rest... );
}