2016-09-12 67 views
10

我使用G ++ 6.1.0(-std=c++14 switch)遇到以下問題,我不明白編譯器爲什麼拒絕代碼。在SFINAE上下文中作爲模板模板參數傳遞的引用類型的別名模板

我有一個輔助結構is_well_formed代替另一種類型的供應到它時檢查,如果提供的模板模板參數很好地形成:

template<template<typename> typename R, typename T, typename = void> 
struct is_well_formed : std::false_type {}; 

template<template<typename> typename R, typename T> 
struct is_well_formed<R, T, void_t<R<T>>> : std::true_type {}; 

我要檢查一個類型是否可引用。所以我的想法是寫:

// (#1) 
template<class T> 
using reference_t = T&; 

static_assert(!is_well_formed<reference_t, void>::value, "Reference to void!?"); 

但我得到一個編譯器錯誤:

main.cpp: In instantiation of 'struct is_well_formed<reference_t, double>': 
main.cpp:62:51: required from here 
main.cpp:54:20: error: type/value mismatch at argument 1 in template parameter list for 'template<template<class> class R, class T, class> struct is_well_formed' 
    : std::false_type {}; 
        ^
main.cpp:54:20: note: expected a class template, got 'reference_t' 
main.cpp:54:20: error: type/value mismatch at argument 1 in template parameter list for 'is_well_formed<R, T, <template-parameter-1-3> >::is_well_formed' 
main.cpp:54:20: note: expected a class template, got 'reference_t' 

或者以下工作以相同的static_assert

// (#2) 
template<class T> 
using reference_t = void_t<T&>; 

此外,以下作品,這讓我很困惑:

// (#3) 
template<class T> 
using pointer_t = T*; 

static_assert(is_well_formed<pointer_t, void>::value, "No pointer to void!?"); 

這三個別名之間有什麼區別?void_t<T&>解決方案最優雅嗎?或者是否可以修改is_well_formed幫助器結構以支持第一個reference版本?

編輯:我測試了MSVC「15」預覽版4和(#1)(#3)包括斷言的代碼。但是,當我嘗試(#2)時,無效參考斷言不起作用,即在替換過程中信息丟失,並且永遠不會選擇過載。哪個編譯器是正確的?

is_well_formed幫助程序對應於can_apply結構體,它曾經在SFINAE上的Stack Overflow文檔頁面中記錄,我剛剛刪除了參數包。完整的示例代碼:

#include <utility> 

// Only defined in std for C++17 
template <class...> 
using void_t = void; 

// (#1) Compiler error during substitution in is_well_formed 
template<class T> 
using reference_t = T&; 

// (#2) Ok, asserts work 
/* 
template<class T> 
using reference_t = void_t<T&>; 
*/ 

// (#3) Ok, asserts work 
template<class T> 
using pointer_t = T*; 

template<template<typename> typename R, typename T, typename = void> 
struct is_well_formed 
    : std::false_type {}; 

template<template<typename> typename R, typename T> 
struct is_well_formed<R, T, void_t<R<T>>> 
    : std::true_type {}; 

int main(int, char**) 
{ 
    static_assert(is_well_formed<reference_t, double>::value, "No reference to double!?"); 
    static_assert(!is_well_formed<reference_t, void>::value, "Reference to void!?"); 

    static_assert(is_well_formed<pointer_t, double>::value, "No pointer to double!?"); 
    static_assert(is_well_formed<pointer_t, void>::value, "No pointer to void!?"); 

    return 0; 
} 
+1

有趣。如果'reference_t'產生一個引用類型,這似乎只會失敗。 –

+1

報告爲https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77575 –

+0

@ T.C。那很快。:D真奇怪,如果這實際上是一個錯誤,沒有人遇到/報告過它 - 這看起來不像是最奇特的代碼... – w1th0utnam3

回答

0

這可能是一個編譯器缺陷和用戶T.C.看到這個帖子後報告說,它在GCC的Bugzilla here。用戶Jarod42提出

template<class T> 
using reference = decltype(std::declval<T&>()); 

爲兩個MSVC15和GCC 6.1.0工作方案。此外,他還指出,MSVC仍然需要很長void_t定義

template <class...> 
struct make_void { using type = void; }; 

template <typename... T> 
using void_t = typename make_void<T...>::type; 

,而不是明顯的

template <class...> 
using void_t = void; 

這阻止選項(#2)在原崗位無法正常工作。

相關問題