2016-09-12 6 views
10

G ++ 6.1.0(-std=c++14スイッチ)で次の問題が発生しましたが、コンパイラがコードを拒否する理由がわかりません。SFINAEコンテキストでテンプレートテンプレート引数として渡される参照型のエイリアステンプレート

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 {}; 

私はタイプが参照可能であるかどうかを確認したい:

私は付属のテンプレートテンプレート引数がうまく形成されている場合、その中に別の供給タイプに置き換えたときにチェックするヘルパー構造体is_well_formedを持っています。

// (#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!?"); 

3つのエイリアスの違いは何ですか?void_t<T&>の解決策はありますか?または、referenceバージョンをサポートするようにis_well_formedヘルパー構造を変更することはできますか?

EDIT:私はMSVC "15" のプレビュー4、およびアサートを含む(#1)(#3)仕事でコードをテストしました。しかし、私が試してみると(#2) void参照のアサートが機能しません。つまり、置換中に情報が失われ、false_typeオーバーロードが選択されません。どのコンパイラが正しいのですか?

is_well_formedヘルパーはcan_apply構造体に対応しています。これは、Stack Overflowのドキュメントページ(SFINAE)に記載されていましたが、パラメータパックを削除しました。完全なサンプルコード:

#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はMSVC15とGCC 6.1.0の両方のための作業の代替として

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

を提案しました。さらに彼は、MSVCはまだ代わりに働いてから、元のポストにオプション(#2)を防ぐ明らか

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

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

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

長いvoid_t定義が必要であることを指摘しました。

関連する問題