C++11 では頻繁に、コンテナーをパラメーターとして受け取る関数を定義する必要があります。
たとえば、関数を定義してみましょうaddup
(はい、単に の単純なバージョンですstd::accumulate
):
template <class I>
int addup (I first, I last)
{
int x = 0;
while ( first != last )
x += *first++;
return x;
}
これは、柔軟で標準ライブラリのイディオムである反復子の範囲を取ります。
ただし、次の関数があるとします。
vector<T> f();
私はこれをしなければなりません:
auto v = f();
int x = addup(v.begin(), v.end());
私はむしろこれをしたい:
int x = addup(f());
私がこれを行うことができるように:
for (auto t : f())
...
範囲ベースの精神で、次のようなものが欲しいです:
template<class C>
int addup(C&& container)
{
addup(beginexpr(container), endexpr(container)); // ???
}
標準では、6.5.4(言い換え)で次のように述べています。
(A) if
container
は配列型でbeginexpr
、endexpr
arecontainer
とcontainer
+bound
はそれぞれ、bound
はバインドされた配列です。(B)
container
がクラス型である場合、非修飾 IDbegin
およびend
は、クラス メンバー アクセス ルックアップ (3.4.5) によるかのように、クラスのスコープ内でcontainer
ルックアップされ、いずれか (または両方) が少なくとも 1 つの宣言を見つけbeginexpr
、endexpr
それぞれ、container.begin() および container.end();(C) そうでない場合、
beginexpr
およびendexpr
はそれぞれbegin(container)
およびend(container)
であり、begin と end は引数依存のルックアップ (3.4.2) でルックアップされます。
addup
4つのケースを処理し、他のオーバーロードと競合しないように、一連のオーバーロードまたは特殊化を定義することは可能ですか? これは、最初に通常のイテレータ ペア関数であり、次に上記の A、B、および C のそれぞれです。どのように?
(これが可能な場合、標準ライブラリがそのようなオーバーロードを提供しないのはなぜですか?)
また、関数がコンテナーを超えて追加のパラメーターを受け取る場合はどうなるでしょうか? オプションの追加パラメーター x
(デフォルト値を持つパラメーター) をすべてに追加しても、次の 2 つの呼び出しがあいまいにならないように、オーバーロードを変更できますか。
addup(v.begin(), v.end());
addup(v, x);
つまり、テンプレート パラメーターが反復子、配列、コンテナー クラスなどである必要があることを ("SFINAE" などを使用して) 静的にアサートし、この情報をオーバーロードの明確化に使用できますか?