GCC是正確的。
讓我們從一個稍微簡單的例子開始,後來證明原來的例子遵循相同的模式:
template<typename T>
void bar(T const&)
{
// Shall not fire
static_assert(std::is_same<T, int>::value, "Error!");
}
int main()
{
int x = 0;
bar(x); // 1 - Assertion won't fire
int const y = 0;
bar(y); // 2 - Assertion won't fire
}
這裏發生了什麼?首先,根據§14.8.2.1/3:
[... ...]如果P是一個參考類型,P引用的類型用於類型推導。 [...]
這意味着該類型的扣將嘗試匹配T const
針對int
(在情況1)和針對int const
(在情況2)。在第二種情況下,用int
代替T
將產生完美匹配,所以很容易;在第一種情況下,我們有const
開始有一個完美的匹配。但是,這是§14.8.2.1/4的用武之地:
[...] 如果原來的P是引用類型,推導A(由參考簡稱,即,類型) 可以是 更CV-合格比轉化A. [...]
在這裏,替換爲int
T
給我們帶來了推導int const
,這是更CV-合格比int
(的類型參數x
)。但由於上述第14.8.2.1/4條,這是可以接受的,所以即使在這種情況下,T
也被推斷爲int
。
現在讓我們來解決您的原來的例子(只是略作調整,但我們會得到原始版本最終):
template<typename T>
void bar(T const&)
{
// Does not fire in GCC, fires in VC11. Who's right?
static_assert(std::is_same<T, char[4]>::value, "Error!");
}
int main()
{
char x[] = "foo";
bar(x);
char const y[] = "foo";
bar(y);
}
除此之外,我換成int
與char []
的事實,這是例子,我第一個例子在結構上是相同的。爲了說明爲什麼這等價成立,考慮下面的斷言(不上觸發任何編譯器,如預期):
// Does not fire
static_assert(
std::is_same<
std::add_const<char [4]>::type,
char const[4]
>::value, "Error");
的C++標準11本任務中的行爲3.9.3款/ 2 :
應用於數組類型的任何cv限定符都會影響數組元素類型,而不是數組類型(8.3.4)。
段落8.3.4/1也規定:
[...]任何類型的形式是「NT的CV-限定符-SEQ陣列」的被調整到「N CV的陣列 -qualifier-seq T「,對於」T的未知範圍數組「也是類似的。可選的屬性說明符seq 屬於數組。 [實施例:
typedef int A[5], AA[2][3];
typedef const A CA; // type is 「array of 5 const int」
typedef const AA CAA; // type is 「array of 2 array of 3 const int」
末端示例] [注:所謂「N- CV-限定符-SEQ的T數組」具有CV-限定類型;見3.9.3。 - 注意]
由於現在很清楚這兩個示例呈現相同的模式,因此應用相同的邏輯是有意義的。這將引導我們走完全相同的推理路徑。
在執行類型扣除時,T const
在第一種情況下與char[4]
匹配,在第二種情況下與char const[4]
匹配。
在第二種情況下,T = char[4]
產生完美匹配,因爲T const
在替換後變爲char const[4]
。在第一種情況下,推導出的A
再次比原始的A
更符合CV條件,其中用char[4]
代替T
得到char const[4]
。但是再一次,14.8.2.1/4允許,所以T
應該推導爲char[4]
。
最後回到你原來的例子。由於字符串文字"str"
還具有類型char const[4]
,T
應當推斷爲char [4]
,這意味着GCC是右:
template<typename T>
void foo(T const&)
{
// Shall not fire
static_assert(std::is_same<T, char[4]>::value, "Error!");
}
int main()
{
foo("str"); // Shall not trigger the assertion
}
兩者都在抱怨沒有'foo'定義.... – UmNyobe 2013-03-19 13:57:34
@UmNyobe是的,我知道,它只需要打印類型 – FrozenHeart 2013-03-19 13:59:20
@UmNyobe我的意思是什麼類型應該在這種情況下 - char [4]或char const [4]? – FrozenHeart 2013-03-19 14:00:08