[英]SFINAE: ambiguous overload if called with no arguments
考慮以下典型的SFINAE測試函數(它檢查類型是否具有begin()
成員函數)
template <class> constexpr bool
has_begin_member (...) { return false; }
template <class T> constexpr bool
has_begin_member (decltype (std::declval <T>().begin ())* = 0) {
return true;
}
我可以用一個參數來稱呼它:
has_begin_member <int> (0); // yields false
但沒有任何論據:
has_begin_member <int> (); // compilation error
它導致以下含糊不清:
error: call of overloaded 'has_begin_member()' is ambiguous
note: candidates are:
note: constexpr bool has_begin_member(...)
note: constexpr bool has_begin_member(decltype (declval<T>().begin())*)
為什么“省略號技巧”在這種情況下不起作用?
編輯:完整程序:
#include <utility>
#include <vector>
template <class> constexpr bool
has_begin_member (...) { return false; }
template <class T> constexpr bool
has_begin_member (decltype (std::declval <T>().begin ())* = 0) {
return true;
}
static_assert (!has_begin_member <int> (0), "broken");
static_assert (has_begin_member <std::vector <int>> (0), "broken");
static_assert (!has_begin_member <int> (), "broken");
static_assert (has_begin_member <std::vector <int>> (), "broken");
int
main (){}
匯編:
g++ -std=c++11 -o toto ./toto.cpp
./toto.cpp:17:58: error: call of overloaded 'has_begin_member()' is ambiguous
./toto.cpp:17:58: note: candidates are:
./toto.cpp:5:5: note: constexpr bool has_begin_member(...) [with <template-parameter-1-1> = std::vector<int>]
./toto.cpp:8:5: note: constexpr bool has_begin_member(decltype (declval<T>().begin())*) [with T = std::vector<int>; decltype (declval<T>().begin()) = __gnu_cxx::__normal_iterator<int*, std::vector<int> >]
對於has_begin_member<int>()
情況,第二個重載不可行,因為模板參數替換失敗,因此只有第一個重載是可行的,因此沒有歧義。
對於has_begin_member<std::vector<int>>()
情況,替換成功,因此有兩個可行的函數。
13.3.2 [over.match.viable]:
- 如果列表中有m個參數,則所有具有m個參數的候選函數都是可行的。
- 具有少於m個參數的候選函數僅在其參數列表(8.3.5)中具有省略號時才可行。 出於重載解析的目的,任何沒有相應參數的參數都被認為是“匹配省略號”(13.3.3.1.3)。
- 僅當(m + 1) -st參數具有默認參數(8.3.6)時,具有多於m個參數的候選函數才是可行的。 出於重載分辨的目的,參數列表在右側被截斷,因此恰好有m個參數。
在這種情況下, m為零,第一個重載是可行的(通過第二個子彈),第二個重載也是可行的(通過第三個子彈)但是為了重載解析的目的,忽略具有默認參數的參數,因此通過比較找到最佳可行功能:
template<> constexpr bool has_begin_member<vector<int>>(...);
template<> constexpr bool has_begin_member<vector<int>>();
這顯然是模棱兩可的,就像這樣:
int f(...);
int f();
int i = f(); // error
調用任一函數都不需要轉換序列,因此它們不能按照具有“更好的轉換序列”的方式進行排序(使用13.3.3.2 [over.ics.rank]中的規則),這意味着它們是曖昧的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.