15

問題

funcフォーム内の任意のコンテナー(Container<Type, N, Args...>つまり、最初のテンプレート引数として型を取り、2 番目としてstd::size_tコンテナー内にいくつの引数があるかを定義するコンテナー)を取りiN4042.

そのようなコンテナの例はstd::array.

関数の最初のバージョンは次のようになります。

template
    < template<class, std::size_t, class...> class Container
    , class Type
    , std::size_t N
    , class... Args >
auto func(std::size_t i, Container<Type, N, Args...>& container) -> decltype(container[0]) { 
    static_assert(N >= 40 && N <= 42, "bla bla bla");
    return container[i];
}

そして、constオーバーロードが必要になります:

template
    < template<class, std::size_t, class...> class Container
    , class Type
    , std::size_t N
    , class... Args >
auto func(std::size_t i, const Container<Type, N, Args...>& container) -> decltype(container[0]) { 
    static_assert(N >= 40 && N <= 42, "bla bla bla");
    return container[i];
}

質問

次のようなものを定義することは可能ですか (これは普遍的な参照ではないため、機能しません):

template
    < template<class, std::size_t, class...> class Container
    , class Type
    , std::size_t N
    , class... Args >
auto func(std::size_t i, Container<Type, N, Args...>&& container) -> decltype(container[0]) { 
    //                                              ^^
    static_assert(N >= 40 && N <= 42, "bla bla bla");
    return container[i];
}

この関数の単一バージョンを定義し、make はContainer<Type, N, Args...>&const Container<Type, N, Args...>&?の両方で機能します。

4

6 に答える 6

3

次のようなことを試してください:

template<typename U, typename T> struct F;
template<template<class, std::size_t, class...> class Container
, class Type
, std::size_t N
, typename T
, class... Args> struct F<Container<Type, N, Args...>, T> {
    static auto func(std::size_t i, T&& t) {
        static_assert(N >= 40 && N <= 42, "bla bla bla");
        return t[i];
    }
}

template<typename U> auto func(std::size_t i, U&& container) { 
    return F<std::decay<U>::type, U>::func(i, container);
}

それだけの価値があるかどうかはよくわかりません。

于 2014-07-26T16:54:29.727 に答える
1

このような質問を見るたびに、SFINAE について考えてみてください。そして、「いや、それは悪い考えだ。別の方法があるに違いない」と考えます。通常、その方法にはタグのディスパッチが含まれます。

タグディスパッチは使えますか?はい、できます

template<class...> struct types{using type=types;};
// in case your C++ library lacks it:
template<class T>using decay_t=typename std::decay<T>::type;
template
< template<class, std::size_t, class...> class Container
, class Type
, std::size_t N
, class... Args
, class Container
>
auto func_internal(
    std::size_t i,
    types<Container<Type, N, Args...>>,
    Container&& container
) -> decltype(container[0]) { 
  static_assert(N >= 40 && N <= 42, "bla bla bla");
  return container[i];
}
template<class Container>
auto func( std::size_t i, Container&& container )
-> func_internal( i, types<decay_t<Container>>{}, std::declval<Container>() )
{
  return func_internal( i, types<decay_t<Container>>{}, std::forward<Container>(container) );
}

func取得し、タイプ情報をタグにラップし、types<?>それを に渡して、タグからfunc_internalすべてのおいしいサブタイプ情報を抽出し、types<?>から転送状態を抽出しましたContainer&&

の本体はfunc単純に に移行されfunc_internal、間違った型が渡されてエラーが発生した場合、エラーはtypes<blah>does not matchになりますがtypes<Container<Type, N, Args...>>、これは悪いエラーではありません。

このような複数のマッチングを 1 つのパラメーターにバンドルすることもできます。

于 2014-07-26T18:58:58.760 に答える
0

C++11 で得られる最も近いものは次のようなものだと思います。

template<class Container>
struct container_traits{};

template<
  template<class, std::size_t, class...> class Container,
  class Type,
  std::size_t N,
  class... Args>
struct container_traits< Container<Type, N, Args ... > >
{
    typedef Type type;
    enum {size = N};
};

template<class Container,
         unsigned N = container_traits< 
                  typename std::remove_reference<Container>::type >::size>
auto func(std::size_t i, Container && container) -> decltype(container[0]) 
{ 
    static_assert(N >= 40 && N <= 42, "bla bla bla");
    return container[i];
}

例:

std::array<int,41> a;
func(41,a); // Ok, pased by lvalue ref.

// "static assert, bla bla bla" (would be passed by rvalue-ref)
func(1, std::array<int,2>{}); 

// Error, no suitable overload overload, the only func available fails with SFINAE
func(15, int{}); 
于 2014-07-26T17:54:28.467 に答える