2015-03-17 10 views
5

std::enable_if kullanarak, foo iki aşırı yüklenmeyi ayırt etmem gereken bir durum var. std::enable_if'un kendisine verilen koşul, foo şablon parametresinin bağımlı tipine bağlıdır.std :: enable_if'in kendisi başka bir koşula bağlı olan bir koşulla nasıl kullanılır?

std::enable_if'u kullanarak bunu ifade etmenin en iyi yolu nedir?

Aşağıdaki test kodu şu ana kadarkilere sahibim. Test kodunda istediğim davranışa ulaşmak için std::enable_if dışında muhtemelen daha iyi yollar olduğunu anlıyorum. Ancak, aşağıdaki, kendi kullanım durumumun std::enable_if gerektirdiği basitleştirilmiş bir sürümüdür.

#include <type_traits> 
#include <cassert> 

struct bar 
{ 
    using baz = int; 
}; 

template<class T> struct is_bar : std::false_type {}; 
template<> struct is_bar<bar> : std::true_type {}; 

template<class Bar> 
struct baz_type 
{ 
    using type = typename Bar::baz; 
}; 


template<class T> 
typename std::enable_if< 
    std::is_integral< 
    typename baz_type<T>::type 
    >::value, 
    int 
>::type 
    foo(T x) 
{ 
    return 7; 
} 

template<class T> 
typename std::enable_if< 
    !is_bar<T>::value, 
    int 
>::type 
    foo(T x) 
{ 
    return 13; 
} 

int main() 
{ 
    assert(foo(bar()) == 7); 
    assert(foo(0) == 13); 

    return 0; 
} 

derleyici çıkışı: foo ilk aşırı kullanılan enable_if iç içe tip T::baz bağlı olduğundan

$ g++ --version ; echo ; g++ -std=c++11 repro.cpp 
g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2 
Copyright (C) 2013 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 


repro.cpp: In instantiation of ‘struct baz_type<int>’: 
repro.cpp:29:3: required by substitution of ‘template<class T> typename std::enable_if<std::is_integral<typename baz_type<Bar>::type>::value, int>::type foo(T) [with T = int]’ 
repro.cpp:49:3: required from here 
repro.cpp:18:33: error: ‘int’ is not a class, struct, or union type 
    using type = typename Bar::baz; 

Bu kod derleme yapmaz. int'un bu yuvalanmış türü olmadığı için kod geçersizdir.

Ne istediğimi ifade etmenin doğru yolu nedir?

+0

"baz_type" bir sınıf şablonu yerine bir diğer ad şablonu yapabilir misiniz? – dyp

+2

Bir alternatif, çeşitli 'enable_if's, ör. varsayılan şablon argümanlarını kullanarak. Birincisi 'is_bar' kontrol etmeli, ikincisi' baz_type :: type' kullanabilir. Standart, sözcüksel olarak değerlendirildiğini bildirir. – dyp

+0

@DanielFrey * shrug * İyimserim var. Yine de çok okunabilir olmasa da, en azından [bu cevap] 'dan sonra değil (http://stackoverflow.com/a/26533335/). – dyp

cevap

2

Aşağıdaki yazıyı Coliru'da yazarken, @dyp zaten kendi yorumunda önemli bir rol gösterdi. Aşağıdaki IMHO oldukça okunaklı ne çalışmak ve ne olduğunu:

template< 
    class T, 
    typename=typename std::enable_if<is_bar<T>::value>::type, 
    typename=typename std::enable_if<std::is_integral<typename baz_type<T>::type>::value>::type 
> 
int foo(T x) 
{ 
    return 7; 
} 

template< 
    class T, 
    typename=typename std::enable_if<!is_bar<T>::value>::type 
> 
int foo(T x) 
{ 
    return 13; 
} 

Live example

14 C++ ile bir hatta kısaltmak için std::enable_if_t kullanırsınız.

+0

Yardımlarınız için teşekkürler! –