2016-01-10 11 views
7

いくつかのテンプレートの制約を試している間は、私がクラン3.7で驚くべき行動に遭遇し、構築します。テンプレート値パラメーターのdecltypeはSFINAEコンテキストをトリガーする必要がありますか?

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; 

このdecltypeは私のコンパイラでSFINAEコンテキストトリガー:

:とは対照的に

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

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

例:

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

これは標準で必要ですか、これは「ラッキーな」コンパイラのバグですか?このようconstraintとして

Wandbox link

答えて

8

エイリアステンプレートは、それらが使用しているすべてのテンプレート定義の中に置換されている彼らは、このように特別なよ:。他のテンプレートを一度明確な引数が供給されている置換されています。

したがって、この宣言:

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

この宣言(暗黙的な変換のためのstatic_castの差である置換)とほぼ同等である。

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

static_castであるときは、このSFINAEを生成無効。

このエフェクトは便利で、基本的には今後のConcepts機能の制約をエミュレートすることができます。しかし、この特定のアプローチはむしろ複雑であり、あなたはそれを実際に活用していません。

正規のSFINAEのアプローチはこれです:

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

あなたはもう少しきれいで賢いこと、および戻り値の型からSFINAEを削除することができます - あなたは現在のために行くように見えるものを:

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

は、図書館の基礎TS内の変数のテンプレートを考えると、これはあなたの例でシンボルのためのシンボルに対応:

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

// constraint  < Pointer   <T>>  = required> 

実際のコンセプトは次のようなものです:

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

template< typename T > 
void foo(Pointer<T>); 
関連する問題