12

私はほとんど実用的な解決策を持っています。ただし、いくつかの単純なケースのコンパイルに失敗し、エラー メッセージを解読できません。

私の現在の解決策:

#define AUTO_RETURN( EXPR ) -> decltype( EXPR ) \
{ return EXPR; }

template< typename BinaryFunc, typename First, typename Second >
auto foldl( BinaryFunc&& func, First&& first, Second&& second )
AUTO_RETURN( func( std::forward<First>(first), std::forward<Second>(second) ) )

template<typename BinaryFunc, typename First, typename Second, typename... Rest >
auto foldl( BinaryFunc&& func, First&& first, Second&& second, Rest&&... rest )
AUTO_RETURN(
   foldl(
      std::forward<BinaryFunc>(func),
      func( std::forward<First>(first), std::forward<Second>(second) ),
      std::forward<Rest>(rest)... )
   )

これは期待どおりに機能します:

struct adder
{
   template< int LHS, int RHS >
   std::integral_constant<int,LHS+RHS>
   operator()( std::integral_constant<int,LHS>, std::integral_constant<int,RHS> )
   {
      return {};
   }
};

auto result = foldl( adder(),
      std::integral_constant<int,19>{},
      std::integral_constant<int,23>{}
   );

assert( result.value == 42 );

ただし、これはコンパイルに失敗します

foldl( adder(),
      std::integral_constant<int,1>{},
      std::integral_constant<int,2>{},
      std::integral_constant<int,3>{},
      std::integral_constant<int,4>{},
   );

std::forward奇妙なことに、コードからすべての右辺値参照を削除すると、正常に動作します

私は何を間違っていますか?
これはコンパイラのバグですか?

4

2 に答える 2

6

C++11のいくつかの新しい領域を調査するきっかけとなったすばらしい質問に感謝します。

Anthony W.は、ソリューションの方が高速でした。しかし、私はまだ私のものを共有したいと思っています。これもヘルパー構造体を使用しています(そしてそれは確かにより冗長です)。まず、可変個引数テンプレート関数でdecltypeを使用して、同様の質問の末尾の戻り型へのリンクを共有しましょう。そこにある答えはヘルパー構造体の同じ考えに基づいているので、彼らの作者は称賛に値します。

以下のコードはideoneでチェックされています。ヘルパー構造体が型を処理するようになったため、AUTO_RETURNを使用しなくなったことに注意してください。

template< typename BinaryFunc, typename First, typename... Types >
struct helper;

template< typename BinaryFunc, typename First>
struct helper<BinaryFunc, First> {
    typedef decltype(std::declval<First>()) type;
};

template< typename BinaryFunc, typename First, typename Second >
struct helper<BinaryFunc, First, Second> {
    typedef decltype(
        std::declval<BinaryFunc>()( std::declval<First>(), std::declval<Second>() )
    ) type;
};

template< typename BinaryFunc, typename First, typename Second, typename... Rest >
struct helper<BinaryFunc, First, Second, Rest...>  {
    typedef typename helper< BinaryFunc,
                             typename helper<BinaryFunc, First, Second>::type,
                             Rest...
                           >::type
                     type;
};

template< typename BinaryFunc, typename First, typename Second >
typename helper<BinaryFunc, First, Second>::type
foldl( BinaryFunc&& func, First&& first, Second&& second ) {
    return func( std::forward<First>(first), std::forward<Second>(second) );
}

template< typename BinaryFunc, typename First, typename Second, typename... Rest >
typename helper<BinaryFunc, First, Second, Rest...>::type
foldl( BinaryFunc&& func, First&& first, Second&& second, Rest&&... rest ) {
   return foldl(
      std::forward<BinaryFunc>(func),
      func( std::forward<First>(first), std::forward<Second>(second) ),
      std::forward<Rest>(rest)...
   );
}
于 2011-05-20T09:27:07.490 に答える
6

問題はdecltype、 variadic の戻り値の型が variadicを認識foldlできないことfoldlです。これは、まだ完全に宣言されていないためです。そのため、それ自体の別のインスタンス化に再帰することはできません。

ヘルパーでそれを行うことができますstruct

template<typename BinaryFunc, typename... Args >
struct folder;

template<typename BinaryFunc, typename First, typename Second>
struct folder<BinaryFunc,First,Second>
{
    static auto foldl( BinaryFunc&& func, First&& first, Second&& second )
        AUTO_RETURN( func( std::forward<First>(first), std::forward<Second>(second) ) )
};

template<typename BinaryFunc, typename First, typename Second, typename... Rest >
struct folder<BinaryFunc,First,Second,Rest...>
{
    static auto foldl(BinaryFunc&& func, First&& first, Second&& second, Rest&&... rest )
        AUTO_RETURN(
            (folder<
            BinaryFunc,
             decltype(func( std::forward<First>(first), std::forward<Second>(second) )),Rest...>::
            foldl(
                std::forward<BinaryFunc>(func),
                func( std::forward<First>(first), std::forward<Second>(second) ),
                std::forward<Rest>(rest)... )
                ))
};

template< typename BinaryFunc, typename... Args >
auto foldl( BinaryFunc&& func, Args&& ... args )
AUTO_RETURN(
    (folder<BinaryFunc,Args...>::foldl(
      std::forward<BinaryFunc>(func),
      std::forward<Args>(args)... ))
   )
于 2011-05-20T08:58:55.800 に答える