2015-12-15 150 views
11

我一直在SVN中使用GCC中的lite概念進行實驗。我遇到了一個我懷疑是由於缺乏理解而導致的問題,如果有人能指出我的方向,我會很感激。我的代碼是:概念和聲明順序

#include <iostream> 
#include <string> 

// Uncomment this declaration to change behaviour 
//void draw(const std::string&); 

template <typename T> 
concept bool Drawable() { 
    return requires (const T& t) { 
     { draw(t) } 
    }; 
} 

void draw(const std::string& s) 
{ 
    std::cout << s << "\n"; 
} 

int main() 
{ 
    static_assert(Drawable<std::string>()); // Fails 
} 

這裏我定義了一個簡單的概念,Drawable,其目的是要求一個給定的const T&類型的參數,功能draw(t)編譯。

然後我定義了一個函數draw(const std::string&),它將字符串「繪製」爲cout。最後,我檢查std::string是否與Drawable概念相符 - 我預料它會這樣做,因爲調用static_assert時適當的draw()函數在範圍之內。

但是,靜態斷言失敗,除非我包含draw(const std::string&)之前的的聲明定義,我不知道爲什麼。

這是預期的行爲與概念,還是我做錯了什麼?

+8

沼澤標準的ADL問題與數百個愚蠢。 ADL不會檢查全局名稱空間,因爲所涉及的類型都不是它的成員。取消註釋模板上方的聲明可以使非限定名稱查找在模板定義上下文中找到它。 – Columbo

+0

所以,如果他把名字空間標準中的無效繪製聲明。它應該工作。 – West

+0

我錯過了開頭句子中的SVN參考。這有什麼重要的意義? –

回答

-1

因爲需要聲明上面的函數,所以使用它的所有函數都需要知道它。

在一個類中,函數在頭文件中聲明。如果他們不是會員,那麼他們需要在使用前聲明。這是因爲編譯器從上到下讀取,並且只有在看到聲明時才瞭解函數。

如果你交換概念代碼和繪圖代碼,它也應該工作。

1

這個問題與ADL無關),而僅僅是名稱查找。 GCC使用的概念草案是n4377,但我將使用的C++標準草案是n4140。首先,在潛入標準之前,我們可以將您的問題轉化爲我們知道應該工作的形式的MCVE。例如:

template<typename T> concept bool C = 
    requires (T a, T b) { 
    a + b; 
    }; 

這是一個簡單的要求,[expr.prim.req.simple],用於檢查表達式的有效性。重寫我們的示例以匹配表單:

template<typename T> concept bool Drawable = 
    requires (const T& x) { 
    draw(x); 
    }; 

我們可以看到我們的語法沒問題。好的,n4377是怎麼說的?

[expr.prim.req]/1 A 需要表達提供一種簡明的方式來對模板參數 明確要求。要求是可以通過名稱查找(3.4)或通過檢查類型 和表達式來檢查 的要求。需求主體由 需求序列組成。這些要求可能涉及本地參數, 模板參數以及從 封閉上下文中可見的任何其他聲明。 ...

有道理。我們知道包含上下文是全局命名空間,那麼n4140是什麼意思?

[basic.lookup.unqual]/1在3.4.1中所列的所有情況下,範圍 中搜索在每個 各個類別的列出的順序聲明;一旦聲明名稱爲 ,名稱查找就會結束。如果沒有發現聲明,該程序是 格式不正確。

在以下功能的 聲明符-ID是命名空間N(其中,只爲博覽會的目的,N可以代表全球範圍內)的成員函數的定義中使用的名稱應當 聲明在使用它之前或在它的塊使用在 其包圍塊(6.3)或一個,應在其在 命名空間N使用前被聲明...

作爲概念appertains到功能,上面的段落適用。