2017-03-18 44 views
2

最近我一直在嘗試C++概念。我從以下範圍擴展文件試圖定義:C++概念相同並可賦值

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4569.pdf

的定義和用途Same是困惑我。由於我未知的原因,作者沒有給出明確的定義。所以我使用:

template <class T, class U> 
concept bool Same() 
{ 
    return std::is_same<T, U>::value; 
} 

的問題是,該文件給出了Assignable定義如下:

template <class T, class U> 
concept bool Assignable() 
{ 
    return Common<T, U>() && requires(T&& a, U&& b) { 
    { std::forward<T>(a) = std::forward<U>(b) } -> Same<T&>; 
    }; 
} 

它不工作(GCC 6.3下):一個簡單的Assignable<int&, int&&>()概念支票給我false (我已經驗證Common部分是確定的)。我必須將Same<T&>更改爲T&才能使其看似工作。在其他一些地方也使用相同的Same<Type>檢查。

我的問題是:

  • 是我的Same定義是否正確?
  • 爲什麼使用Same<T&>代替T&?有什麼區別?

感謝您的幫助。

回答

3

在週末攻擊問題後,我想我自己找到了答案。

Eric Niebler和Casey Carter對Same有更精確的定義,它支持多個模板參數(不只是兩個),但我的定義應該基本上適用於雙參數的情況。

使用-> Type時,其目的是將括號中的表達式隱式轉換爲Type。當使用-> Same<Type>時,其目的在於括號中的表達式恰好是Type。所以他們是不同的。

但是,有一個問題。約束檢查非常複雜,甚至像Eric和Casey這樣的專家在N4569中犯了錯誤並給出了錯誤的定義。埃裏克討論GitHub上的問題:

https://github.com/ericniebler/stl2/issues/330

使用時它在N4569給出的方式,這意味着表達應該能夠被傳遞到一個想象的函數模板一樣

template <typename U> 
f(U) 
requires Same<T&, U>() 

這不起作用 - 如果傳遞的表達式是T的左值,則推導出的UT而不是T&。解決方法是在Assignable中使用Same<T&>&&。這將導致以下想象的函數模板:

template <typename U> 
f(U&&) 
requires Same<T&, U>() 

現在一切都OK,如果傳入的表達是T左值U必須推導出T&

玩概念對我來說是一個很好的做法,但我可能應該儘早找到他們的代碼。他們有一個完整的概念,在下面的GitHub庫:

https://github.com/CaseyCarter/cmcstl2

有意用C++的人概念應考慮它。

+1

「Same」的定義有點微妙:範圍TS要求實現將約束'Same ()'視爲等同於'Same ()'。這是不可能的,任何簡單的定義。它不能用語言表達,並且有效地要求通過編譯器內在實現'Same'。 – Casey

+0

對於'Assignable'中例舉的問題的評估,您是完全正確的:當我實現cmcstl2時,GCC中的演繹約束被破壞,並且在開發幾乎等價的解決方法語法時巧妙地誤解了語義。因此,直到最近我們才意識到TS中的概念定義已被打破。 – Casey

+0

@Casey我實際上會認爲你的bug更多的是當前概念提案的失敗。使用'相同的 &&'看起來很醜並且不直觀。 –

3

Same定義的問題是一個比較微妙:在範圍TS需要實施對待約束Same<T, U>()等同於Same<U, T>(),即承認「T是同一類型U」對稱性:

template <class T, class U> 
requires Same<T, U>() 
void foo(); // #1 

template <class T, class U> 
requires Same<U, T>() 
void foo(); // redeclaration of #1 

template <class T> 
requires Same<int, T>() 
void bar(); // #2 

template <class T> 
requires Same<T, int>() 
void bar(); // redeclaration of #2 

這等價不能在語言來表達,因爲對於約束的規範化規則相認的:

is_same_v<T, U> 
is_same_v<U, T> 
is_same_v<T, int> 
is_same_v<int, T> 

作爲不同的原子約束。這需要通過編譯器內在實現Same

+0

感謝您的回答。你是否有現實世界或人爲因素導致問題出現?對不起,我無法弄清楚。 –

+0

我不知道約束泛型代碼的現實世界中的例子自然會導致這樣的情況。安德魯薩頓可能知道一些? IIRC最初的建議是來自他的。 – Casey