10

テンプレート化された (STL) コンテナーを使用する関数を提供する方法を探していますが、その要素は特定の型 (例: int) である必要があります。

これらの関数呼び出しは有効である必要があります。

std::vector<int> Argument;
void foo( Argument );

std::list<int> Argument
void foo( Argument );

std::deque<int> Argument
void foo( Argument );

...etc

これらの関数呼び出しは無効である必要があります:

std::vector<float> Argument;
void foo( Argument );

std::list<double> Argument
void foo( Argument );

std::deque<char> Argument
void foo( Argument );

...etc

コンテナが受け入れられるように「foo」をテンプレート化する方法はありintますが、異なる要素タイプのコンテナは受け入れられませんか?

ベスト、ベン

4

5 に答える 5

13

標準ライブラリのセマンティクスを使用します:

  • コンテナではなく、イテレータのペアを渡しfooます。これにより、関数がより一般的になります
  • std::iterator_traits<Iterator>::value_type値の型を取得するために使用します
  • static_assertIterator の値の型int(または任意の型)

例 :

#include <list>
#include <vector>

template<typename Iterator>
void foo(Iterator begin, Iterator end)
{
    static_assert(std::is_same<int, typename std::iterator_traits<Iterator>::value_type>::value, 
                                "Invalid value type : must be int");
}

int main() {
    std::list<int> l1;
    std::vector<int> v1;

    foo(std::begin(l1), std::end(l1)); // OK
    foo(std::begin(v1), std::end(v1)); // OK

    std::vector<float> v2;
    foo(std::begin(v2), std::end(v2)); // Doesn't compile
}

ライブデモ

ノート:

  • コンテナーの特定のメンバー関数にアクセスする必要がある場合 foo(Deduplicator で指摘されているように、これはパフォーマンス上の理由で発生する可能性があります)、次のContainer引数に固執する必要がある場合があります。

例:value_type ( MooingDuck が指摘しているように、 に到達するための違いに注意してください。これは、配列で動作させるために必要です):

template <typename Container>
void foo(const Container& c)
{

    static_assert(std::is_same<int, std::iterator_type<decltype(std::begin(c))>::value_type>::value, "Invalid value type : must be int");

   // Use c member function(s)
}
于 2014-08-20T20:24:51.193 に答える
9

STL コンテナには がtypedef value_typeありますので、それを使用できます。

次に、次のように禁止できますstatic_assert

template <typename Container>
void foo(const Container& )
{
    static_assert(std::is_same<int, typename Container::value_type>::value, "expect int type");
}

またはSFINAE経由

template <typename Container>
typename std::enable_if<std::is_same<int, typename Container::value_type>::value>::type
foo(const Container& )
{
}
于 2014-08-20T20:22:17.863 に答える
4

次のように、単純に Sfinae を使用できます。

#include <type_traits>
#include <utility>

template <typename Container>
typename std::enable_if< std::is_same< typename Container::value_type, int >::value,
void >::type foo(Container& c) {
  /* code here */
};

コンテナに「int」と同じ値の型がない場合、「foo」のオーバーロードのセットから削除されます。is_convertible関連する型をより受け入れるなど、他の特性を使用することもできます。値として int を持たないコンテナーで foo を呼び出すと、適切なオーバーロード候補がないことがコンパイラーによって報告されます。

C++11 をサポートしていない場合、上記で使用したものは C++98/03 の代替として Boost で利用できます。

于 2014-08-20T20:24:58.067 に答える
3

テンプレート テンプレート パラメータを使用した別のソリューション

template<template<typename, typename...> class Container, typename... Params>
void foo(Container<int, Params...> const&)
{
  ...
}

vectorこれは、listまたはdequeコンテナ内の要素のタイプが である限り一致しintます。

ライブデモ

于 2014-08-20T20:37:16.013 に答える
0

反復可能な範囲が必要であると仮定します。

template<class I>
using value_type_t=typename std::iterator_traits<I>::value_type;

C++14 では廃止:

template<class T>using decay_t=typename std::decay<T>::type;
template<bool b,class T=void>using enable_if_t=typename std::enable_if<b,T>::type;

それで:

namespace adl_details{
  using std::begin;
 template<class C>using iterator_type=decay_t<decltype(begin(std::declval<C>()))>;
}
using adl_details::iterator_type;


template<class C>
enable_if_t<std::is_same<int, value_type_t<iterator_type_t<C>>>::value>
foo(C&& c){
}

その性質を持っています。

于 2014-08-20T23:01:45.947 に答える