2014-01-10 9 views
5

関数には、整数のコンテナ型にのみ関数を制限するenable_ifステートメントがあるにもかかわらず、両方の関数呼び出しで「非積分過負荷」が出力されます。何故ですか?解像度がオーバーロードされて最初の機能が選択されないのはなぜですか?

#include <iostream> 
#include <vector> 
#include <type_traits> 

template<bool B, typename V = void> 
using enable_if = typename std::enable_if<B, V>::type; 

template<typename ForwardIt> 
auto f(ForwardIt first, ForwardIt) 
    -> enable_if<std::is_integral<decltype(*first)>{}> 
{ 
    std::cout << "Integral container type" << std::endl; 
} 

template<typename ForwardIt> 
void f(ForwardIt, ForwardIt) 
{ 
    std::cout << "Non-integral container type" << std::endl; 
} 

int main() 
{ 
    struct X { }; 

    std::vector<int> iv; 
    std::vector<X> xv; 

    f(iv.begin(), iv.end()); // "Non-integral container type" 
    f(xv.begin(), xv.end()); // "Non-integral container type" 
} 

私も2番目のオーバーロードではなく、無駄にenable_if<!std::is_integral<...>>を使用してみました。

答えて

6

イテレータのタイプがfooの場合、decltype(*foo)foo::value_type&になります。参照型は絶対不可欠ではありません。あなたは簡単にstd::decay変換型特性で行われstd::is_integral形質と種類を評価する前に(IIRC、だけでなく、おそらくCV-資格)の参照を削除する必要があります。

template<bool B, typename V = void> 
using enable_if = typename std::enable_if<B, V>::type; 

template<typename T> 
using decay = typename std::decay<T>::type; 

template<typename ForwardIt> 
auto f(ForwardIt first, ForwardIt) 
    -> enable_if<std::is_integral<decay<decltype(*first)>>{}> 
{ 
    std::cout << "Integral container type" << std::endl; 
} 

これは、と曖昧になります両者が一致するので、あなたの他の過負荷は今一致します。あなたは、OPで示唆するように、2番目の過負荷を抑制する必要があります。

8

もう1つの答えですでに問題が説明されていますが、もっと良い解決策があると思います。

イテレータタイプが指すタイプを抽出する場合は、iterator_traitsを使用してください。あなたのコードでは、最初に過負荷を変更します。

template<typename ForwardIt> 
auto f(ForwardIt first, ForwardIt) 
    -> enable_if<std::is_integral<typename std::iterator_traits<ForwardIt>::value_type>{}> 
{ 
    std::cout << "Integral container type" << std::endl; 
} 

と第二に、追加!と同じを使用しています。これはコードが何をするかについてはっきりしているので、より説明的です。 C++ 03でコンパイル*のみ*解決のための

Live example

+0

+1。さて、C++ 03 + TR1、とにかく。 – Casey