簡體   English   中英

SFINAE:如果沒有參數調用,則會出現模糊的重載

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM