2017-05-04 61 views
5

我已經簡化的代碼版本:繼承與is_detected_v提供了一種奇怪的結果(C++ 17)

#include <experimental/type_traits> 

template<class T> using has_data_t = decltype(T::data()); 

template <class B> constexpr auto get_data() { 
    return std::experimental::is_detected_v<has_data_t, B>; 
} 

template <typename Topt> struct opt_base { 
    static constexpr bool i = get_data<Topt>(); 
    //static constexpr auto j = get_data<Topt>(); // fail to compile 
}; 

struct opt : public opt_base<opt> { 
    static int data() { return 7;} 
}; 

int main() { 
    static_assert(std::experimental::is_detected_v<has_data_t, opt>); 
} 

此代碼編譯。但是,如果您將取消註釋註釋行,則斷言失敗。它使用GCC 7.1和Clang 4.0.0進行測試。編譯參數:-std = C++ 1z -O3 -Wall。 Demo

回答

7

在此代碼:

static constexpr bool i = get_data<Topt>(); 
static constexpr auto j = get_data<Topt>(); 

Topt(即opt)尚未完成。所以is_detected_v<has_data_t, opt>應該是false。但是,當我們到達main時,opt完成。所以我們預計is_detected_v<has_data_t, opt>true

有一個模板,當在不同的上下文中實例化時產生不同的結果意味着你的程序不合格,不需要診斷。見[temp.point]:

任何模板的專門化可能在多個翻譯單元中具有實例化點。如果兩個不同的實例化點根據一個定義規則爲模板專門化提供了不同的含義,則該程序不合格,不需要診斷。

添加的j其實並不重要 - 它只是發生翻轉,改變的編譯器選擇實例事情的方式順序開關。該程序不合格,不管j是否存在。

+1

這裏什麼名字是不依賴的? –

+0

@ T.C Hm。這些註釋中的例子都不適用於這裏,還是完全是錯誤的文本?很確定這個例子出於某種原因是不合格的ndr。 – Barry

+0

我認爲[\ [temp.point \]/8](http://eel.is/c++draft/temp.point#8)更相關。 – cpplearner