2016-01-10 24 views
7

bazı şablon kısıtlaması deneme yaparken ben Clang 3.7 şaşırtıcı bir davranış karşılaştı, yapıları:Bir şablon değeri parametresinde decltype, bir SFINAE bağlamını tetiklemeli mi?

struct constraint_success {}; 
struct constraint_failure {}; 

template<bool> 
struct require_t {}; 

template<> 
struct require_t<true> { 
    static constexpr constraint_success* result = nullptr; 
}; 

template<> 
struct require_t<false> { 
    static constexpr constraint_failure* result = nullptr; 
}; 

template<bool Condition> 
constexpr auto require = require_t<Condition>::result; 

//A named dummy value, since we need a default 
constexpr constraint_success* required = nullptr; 

Bu decltype benim derleyicisi SFINAE bağlamını tetikler:

: aksine

template<constraint_success* value> 
using constraint = decltype(value); 

//template<constraint_success* value> 
//using constraint = constraint_success*; 

Örnek:

//define custom constraints 
template<typename T> 
constexpr auto Pointer = require<std::is_pointer<T>::value>; 

template<typename T> 
constexpr auto NotPointer = require<!std::is_pointer<T>::value>; 

//constrain template parameters 
template<typename T, constraint<Pointer<T>> = required> 
void foo() { 
    std::cout << "Hello, pointer!\n"; 
} 

template<typename T, constraint<NotPointer<T>> = required> 
void foo() { 
    std::cout << "Hello, not pointer!\n"; 
} 

int main() { 
    foo<int*>(); 
    foo<int>(); 
    return 0; 
} 

bu standardın gerektirdiği mi, yoksa bu "şanslı" derleyici hata olduğunu? Böyle constraint olarak

Wandbox link

cevap

8

Alias ​​şablonları onlar kullanılan tüm şablon tanımı içinde ikame edilir Onlar bu şekilde özelsin. Diğer şablonlar kez kesin argüman ikame edilir.

Böylece bu beyan: static_cast olduğunda

template<typename T, decltype(static_cast<constraint_success*> 
             (require_t<std::is_pointer<T>>::result)) 
           = required> 
void foo(); 

Bu SFINAE üretir:

template<typename T, constraint<Pointer<T>> = required> 
void foo(); 

bu beyan (gizli bir dönüşüm için static_cast farkı olarak ikame) genel olarak benzer geçersiz.

etkisi yararlıdır, ve esasen yaklaşan Kavramlar özelliği sizi kısıtlamaları taklit sağlar. Bununla birlikte, bu özel yaklaşım oldukça karmaşıktır ve gerçekten bunu kullanmıyorsunuz.

template< typename T, 
    std::enable_if_t< std::is_pointer<T>::value > * = nullptr > 
void foo(); 
: göründüğün gibi şu anda için gidiyor gibi -

template< typename T > 
std::enable_if_t< std::is_pointer<T>::value > foo(); 

Biraz daha temiz ve akıllı olmalı ve dönüş türünden SFINAE kaldırabilirsiniz:

kanonik SFINAE yaklaşımı

şudur

template< typename T, 
    std::enable_if_t< std::is_pointer_v<T> > * = nullptr > 
void foo(); 

// constraint  < Pointer   <T>>  = required> 
: Kütüphane Temelleri TS değişken şablonları Verilen

, bu sembolü-sembolü için örnekle karşılık

gerçekten Kavramlar-imsi yolu şu şekildedir:

template< typename T, std::enable_if_t< std::is_pointer<T>::value > * = nullptr > 
using Pointer = T; 

template< typename T > 
void foo(Pointer<T>);