3

質問を変更したため、これは以前の投稿の再話です(そのため、おそらく新しい質問としてフラグが立てられず、見逃されました)。うまくいけば、私もそれをトリミングします。

次のような機能がありました:

#include <cstddef>
#include <type_traits>

template < typename E, typename T >
inline constexpr
auto  checked_slice( E &&, T &&t ) noexcept -> T &&
{ return static_cast<T &&>(t); }

template < typename E, typename T, std::size_t N, typename U, typename ...V >
inline constexpr
auto  checked_slice( E &&e, T (&t)[N], U &&u, V &&...v )
 -> typename remove_some_extents<T, sizeof...(V)>::type &
{
    typedef typename std::remove_reference<U>::type                 u_type;
    typedef typename std::common_type<u_type, std::size_t>::type  cmp_type;

    return ( u < u_type{} ) || ( static_cast<cmp_type>(u) >=
     static_cast<cmp_type>(N) ) ? throw e : checked_slice( static_cast<E &&>(e),
     t[static_cast<U &&>( u )], static_cast<V &&>(v)... );
}

whereは、メタ関数を特定の回数remove_some_extents呼び出すようなカスタム クラス テンプレートです。std::remove_extent

Whatever(&)[X][Y]プログラムを実行しようとすると、「型の式からの型の参照の初期化が無効ですWhatever(*)[Y]」(またはWhatever(&)[Z]からWhatever*)のような一連のエラーが発生しました。if私の回避策は、条件式を-elseペアに変換することでした(そして を削除しますconstexpr)。

何が問題なのかを突き止めようとしているので、C++ (2011) 標準の条件演算子に関するセクションを調べています。それがセクション 5.16 です。2 つの可能なアクションの 1 つが throw コマンド (またはそれ以外の場合はvoid式) である場合、条件は他の式の型を持ちますが、配列からポインターへの変換を含む標準の変換がその他の式に適用されます。(これは段落 2 にあります。) それが私をめちゃくちゃにしていると思います。それを回避する方法はありますか?配列参照を返すと、a-to-p 変換が抑制されると思いました。にすると機能するのはなぜif/elseですか?

4

1 に答える 1

4

あなたの分析は正しいです。voidこのような状況では、2 つのオペランドの型が異なる場合に何が起こるかを模倣するために、非オペランドが「崩壊」する (つまり、通常の変換が実行される) のではないかと思います。条件式はprvalueです。

条件式の値カテゴリと型の両方が確実にわかっている状況の 1 つは、2 つのオペランドが完全に一致する場合です。したがって、それを有利に使用できます。

cond ? (throw e, t) : t

配列参照型の左辺値になります。(もちろん、最後のオペランドは文字通りである必要はありませんt。ここで再帰呼び出しをプラグインしても問題ありません。)

if/を使用する場合、そのようなハードルに遭遇することはありませelseん。ステートメントとして、言語はその共通の型と値のカテゴリを指定する必要がないからです。

于 2013-04-27T00:52:56.800 に答える