なぜコンパイラは、次の例では、私の関数テンプレートのオーバーロードを選択されていませんか?
-
21-09-2019 - |
質問
次の関数テンプレートが与えられます:
#include <vector>
#include <utility>
struct Base { };
struct Derived : Base { };
// #1
template <typename T1, typename T2>
void f(const T1& a, const T2& b)
{
};
// #2
template <typename T1, typename T2>
void f(const std::vector<std::pair<T1, T2> >& v, Base* p)
{
};
なぜ以下のコードは、常に呼び出すには#1の代わりに、過負荷#2に過負荷をかけるということですか。
int main()
{
std::vector<std::pair<int, int> > v;
Derived derived;
f(100, 200); // clearly calls overload #1
f(v, &derived); // always calls overload #1
return 0;
}
f
の2番目のパラメータはBase
の派生型であることを考えると、私はそれが過負荷#1におけるジェネリック型よりも一致であるとして、コンパイラは#2を過負荷選ぶだろうと期待していた。
はありますmain
機能で表示されているように、ユーザがコードを書くことができるように、私は、これらの機能を書き換えるために使用することができるとの任意の技術(すなわち、引数の型のコンパイラ控除を活用)?
解決
あなたはどちらかこれを行うことができます:
f(v, static_cast<Base*>(&derived));
または選択候補として第一の機能を除去するSFINAEを使用
// Install boost library and add these headers:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
// #1 - change it to look like this (note the keyword void changed positions)
template <typename T1, typename T2>
typename boost::disable_if<
typename boost::is_convertible<T2, Base*>, void>::type
f(const T1& a, const T2& b)
{
};
// #2 - this one can stay the same
template <typename T1, typename T2>
void f(const std::vector<std::pair<T1, T2> >& v, Base* p)
{
};
他のヒント
が与えられると、Fの2番目のパラメータは、ベースの派生型であること
これは、このようなに変換可能だが、それは派生*です。最初のテンプレート関数は変換を必要とせず、第二のものを必要とし、したがって、最初に選択されます。
これは第二の選択
f(v, static_cast<Base*>(&derived));
サイドノート、main
戻りint
オン
多かれ少なかれウェル(コンパイラによって実装されているケーニッヒのルックアップについて明らかトピックの横に特に古いものは)非常に問題となる、テンプレートの特殊のに関するいくつかの落とし穴があります。
専門は(確か、STDがこれをどのように定義されていないが、私の経験から[GCC、MSVC] A派生クラスが一致しません)完全に一致するタイプが必要です。あなたがベース*に醜いキャストを追加した場合、それはあなたが意図するように、必要に応じて派生...
のために別の特殊化を追加します動作するはずです所属していません StackOverflow