2016-09-12 35 views
10

G ++ 6.1.0 (-std=c++14 anahtarı) ile ilgili bir sorunla karşılaştım ve derleyicinin kodu neden reddettiğini anlamıyorum.Başvuru türü için Alias ​​şablonu şablon şablonu argümanı olarak SFINAE bağlamında iletildi

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

Bir tür referans verilebilir olup olmadığını kontrol etmek istiyorum:

Ben verilen şablon şablon argümanı biçimi doğruysa içine başka verilen türünü değiştirirken kontrol eden bir yardımcı yapı is_well_formed var. Yani benim fikrim şu yazmaktı:

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

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

Ama derleyici hatası alıyorum: Ayrıca aşağıdaki

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

: Aynı static_assert ile Alternatif aşağıdaki işler

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' 

Beni gerçekten yapan bulmacalar:

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

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

Üç takma ad arasındaki fark nedir?void_t<T&> çözümü en zarif olanı mı? Veya ilk reference sürümünü desteklemek için is_well_formed yardımcı yapısını değiştirmek mümkün mü?

DÜZENLEME

: Ben msvc "15" Önizleme 4 ve (#1) ve iddia dahil (#3) çalışma ile kod test etti. Ancak, (#2)'u denediğimde, geçersiz referansın iddiası çalışmaz, yani, ikame sırasında bilgi kaybolur ve false_type aşırı yüklenme asla seçilmez. Hangi derleyici doğru?

is_well_formed yardımcı kez SFINAE üzerinde yığın taşması dokümantasyon sayfasından belgelendi gelen can_apply yapı tekabül, sadece parametre paketlerini kaldırıldı. Tam örnek kod:

#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

İlginç. Bu, yalnızca 'reference_t' bir referans tipi sağladığında başarısız olur. –

+1

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

+0

@ T.C olarak rapor edildi. Eh, bu hızlıydı.: D Bu gerçekten bir böcek ve kimse daha önce karşılaştığı/bildirdiği için gerçekten garip - bu en egzotik kod gibi görünmüyor ... – w1th0utnam3

cevap

0

Bir derleyici hata olabilir ve kullanıcı T.C. bu yazıyı gördükten sonra GCC Bugzilla'sına here üzerine bildirildi. Kullanıcı Jarod42 MSVC15 ve GCC 6.1.0 ikisi için çalışan bir alternatif olarak

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

önerdi. Üstelik o MSVC hala uzun void_t tanımını yerine çalışmasını orijinal sonrası seçeneği (#2) engelledi bariz

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

ait

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

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

gerektirdiğini kaydetti.