How to make these std::function parameters unambiguous?という質問を読んだ後、私は完全に混乱しています。、これまでのところ、関数テンプレートの半順序付けとは何かを理解していると思っていましたが、その質問を読んだ後、コンパイラの動作を確認するために 3 つの例を書き留めましたが、受け取った結果は理解しにくいものです。
例 #1
template <class T>
void foo(T) {}
template <class T>
void foo(T&) {}
int main()
{
int i;
foo<int>(i); // error: call is ambiguous!
}
質問:両方の関数が実行可能であることは明らかですが、T&
より専門化されたものではありませんT
か? 代わりに、コンパイラはあいまいな呼び出しエラーを発生させます。
例 #2
#include <iostream>
template <class T>
struct X {};
template <>
struct X<int>
{
X() {}
X(X<int&> const&) {} // X<int> is constructible from X<int&>
// note: this is not a copy constructor!
};
template <>
struct X<int&>
{
X() {}
X(X<int> const&) {} // X<int&> is constructible from X<int>
// note: this is not a copy constructor!
};
template <class T>
void bar(X<T>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template <class T>
void bar(X<T&>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
int main()
{
bar<int>(X<int>()); // calls void bar(X<T>) [with T = int]
bar<int>(X<int&>()); // calls void bar(X<T&>) [with T = int]
}
質問:T&
例 1 でandT
があいまいな場合、なぜここで none 呼び出しがあいまいなのですか? X<int>
から構築可能でX<int&>
あり、提供されたX<int&>
コンストラクターのX<int>
おかげで から構築可能です。コンパイラによって生成されたX<int>::X(X<int> const&)
コピー コンストラクターが ,よりも優れた変換シーケンスX<int>::X(X<int&> const&)
であるためでしょうか (そうであれば、何が優れているか、引数が値によって渡されることに注意してください)、特殊化の順序はまったく問題ではありませんか?
例 #3
#include <iostream>
// note: a new type used in constructors!
template <class U>
struct F {};
template <class T>
struct X
{
X() {}
template <class U>
X(F<U> const&) {} // X<T> is constructible from any F<U>
// note: it takes F type, not X!
};
template <class T>
void qux(X<T>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template <class T>
void qux(X<T&>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
int main()
{
qux<int>(F<int>()); // calls void qux(X<T&>) [with T = int]
qux<int>(F<int&>()); // calls void qux(X<T&>) [with T = int]
}
質問:これは、リンクされた質問から「ラムダ[](int){}
をstd::function<void(int&)>
および に一致させる」のと同様のシナリオです。std::function<void(int)>
両方の呼び出しで、より特化した関数テンプレートが選択されるのはなぜですか? 変換シーケンスが同じなので、半順序が問題になり始めたからですか?
すべてのテストは GCC 4.9.0 で実行され-std=c++11
、追加のフラグはありません。