2012-08-24 40 views
4

考慮以下典型SFINAE測試功能(它檢查是否一個類型具有begin()成員函數)SFINAE:如果調用無參數曖昧過載

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 

它會導致以下不確定性:

爲什麼在這種情況下「省略技巧」不起作用?

編輯:完整的程序:

#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> >] 
+0

你使用什麼編譯器? –

+0

g ++(GCC)4.7.1 20120721(預發佈) – manu

+1

我認爲這看起來像GCC診斷,但它對我來說也適用於G ++ 4.5,4.6,4.7,4.8和Clang ++。請顯示一個完整的示例程序來演示錯誤,我顯然不會像您一樣測試相同的東西。 –

回答

3

對於has_begin_member<int>()情況下,第二過載是不可行的,因爲模板參數替換失敗,所以纔有了第一個重載是可行的,所以沒有歧義。

對於has_begin_member<std::vector<int>>()案例替換成功,所以有兩個可行的功能。

13.3.2 [over.match.viable]:

  • 如果有參數列表中的,具有正好參數是可行的所有候選的功能。
  • 只有在其參數 列表(8.3.5)中有一個省略號時,參數才具有可行性,但參數少於m。出於重載解析的目的,任何沒有相應參數的參數都被認爲是「匹配省略號」(13.3.3.1.3)。
  • 具有多於參數候選功能是可行的只有當(M + 1) -st參數具有 默認參數(8.3.6)。出於超負荷分辨率的目的,參數列表在右側被截斷爲 ,以便確切地具有參數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]中的規則),意味着他們不明確。

+0

好的,因爲在那種情況下沒有轉換,所以省略號的東西不起任何作用,對吧? – manu

+0

是的,請參閱我在答案末尾添加的額外示例。 –