3

多次元配列 (任意のランク) の特定のサンプリング座標で線形補間を実行する汎用フィルタリング関数を作成しようとしています。このためには、値とそれに関連付けられた型に到達するまで、配列のすべての次元をたどる再帰関数テンプレートが必要です。ディメンションの反復処理を停止するタイミングを検出するために、boost::enable_if を使用します。戻り値/型を最上位の関数に「パーコレート」しようとするまで、問題なく動作します。この目的のために、C++0x の型推論を使用しようとしましたが、boost::enable_if とうまく組み合わせられないようです。

問題を次のように切り分けました。

template< typename T, std::size_t I >
auto test(const T &t) -> typename boost::enable_if_c< (I == 0), typename T::value_type >::type
{
    return t[0];
}

template< typename T, std::size_t I >
auto test(const T &t) -> typename boost::enable_if_c< (I > 0), decltype(test< T, I - 1 >(T())) >::type
{
    return test< typename T::value_type, std::size_t(I - 1) >(t[0]);
}

コンパイラ (GCC 4.6) は、次のコードで不平を言います:

typedef std::array< std::array< float, 1 >, 1 > myarray;
myarray ma;
std::cout << typeid (test< myarray, 1 >(ma)).name() << std::endl;

エラーメッセージ:

error: conversion from 'boost::enable_if_c<true, float>::type' to non-scalar type 'boost::enable_if_c<true, std::array<float, 1u> >::type' requested

test< T, I - 1 > の戻り値を使用するように指示されているにもかかわらず、decltype は test< T, I > の戻り値を使用しているようです。この動作が発生する理由は何ですか? 今のところ、全体をファンクターに変えるだけだと思います...

4

1 に答える 1

4

問題は、T() (および T) を decltype に渡したということです。タイプは折りたたまれていません。これは、return 式を decltype に渡したものと比較すると明らかに明らかになり、矛盾しています。

template< typename T, std::size_t I >
auto test(const T &t) -> typename boost::enable_if_c< (I > 0), decltype(test< T, I - 1 >(T())) >::type
{
    return test< typename T::value_type, std::size_t(I - 1) >(t[0]);
}

decltype: test<T

return expression: test< typename T::value_type

このような forward 関数を定義する場合、戻り値の型を定義するために使用される decltype-expression は、ほとんどの場合、実際の戻り値の式とまったく同じにする必要があります。

編集:実際には、特にテンプレートに左辺値を渡す場合は、右辺値を渡してはならないことを追加する必要があります。異なる結果になる可能性があるためです。

于 2011-01-20T23:19:41.850 に答える