2012-02-14 18 views
0

enable_ifに頼らずに他のオーバーロードがすべて失敗しない限り、テンプレートオーバーロードを確実に選択する方法はありますか?他のオーバーロードが失敗した場合にのみテンプレートされたオーバーロードを使用してください

intは長いオーバーロードで処理する必要がありますが、テンプレートオーバーロードによって処理されていますが、コンパイラはそれが好きではありません。

class SetProxy { 
public: 
    void operator=(const TemplateString& value) { 
    dict_.SetValue(variable_, value); 
    } 

    template<class T> 
    void operator=(const T& value) { 
    dict_.SetValue(variable_, TemplateString(value.data(), value.size())); 
    } 

    void operator=(long value) { 
    dict_.SetIntValue(variable_, value); 
    } 
} 
+0

なぜテンプレート以外のバージョンが必要ですか?なぜあなたはテンプレートを特化できないのですか? –

+0

問題を再現できません。 –

答えて

0

質問のコードの問題は、longまたはTemplateStringに変換可能な引数が渡された場合、テンプレートが最もよく一致することです。テンプレートは変換を行う必要はなく、他の関数を呼び出す際には変換が必要です。

std::enable_ifを使用しなくても目的の動作を達成できますが、std::enable_ifの使用は禁止されていると考えられますが、C++ 2011やBoostを使用できない場合でも非常に簡単ですstd::enable_ifを実装します。望ましい型の特性のいくつかを実装することは少し困難ですが実行可能です。その使用を効果的に制限するということは、本質的に同じ論理を実際に何を言わないように、多かれ少なかれ工夫して実装する必要があることを意味します。たとえば、このコードはstd::enable_ifまたはSFINAEを使用しませんが、SFINAEが使用されていた場合に必要とされない、実際に作成され、余分なオブジェクトがある:

#include <iostream> 
#include <string> 

class SetProxy { 
    template <typename F> 
    struct helper { 
     helper(F const& v): value_(v) {} 
     F const& value_; 
    }; 

    template<typename F> 
    void aux(helper<F> value, ...) { 
     std::cout << "template " << value.value_ << "\n"; 
    } 
    template<typename F> 
    void aux(long value, int) { 
     std::cout << "long: " << value << "\n"; 
    } 
    template<typename F> 
    void aux(std::string const& value, int) { 
     std::cout << "string: " << value << "\n"; 
    } 
public: 
    template<typename T> 
    void operator=(const T& value) { 
     this->aux<T>(value, 0); 
    } 
}; 

struct foo {}; 
std::ostream& operator<< (std::ostream& out, foo const&) { 
    return out << "foo"; 
} 

int main() 
{ 
    SetProxy p; 
    p = 17l; 
    p = 17; 
    p = foo(); 
    p = "hello"; 
    p = std::string("hello"); 
} 

は、これは、元のタイプを使用していません私はそれらをアクセス可能にしていないので、私は実際の質問に関係のないものをタイプするように感じなかったので、質問。これには、std::is_convertibleの実装の重要なビットが効果的に含まれていることに注意してください。内部的には、代入演算子に可変引数リストを持たせることができないため、別のテンプレートに転送する必要があります。intからhelper<int>への実行可能な変換があるため、型を区別するその他のものがなければあいまいさがありますテンプレートのバージョンを少し悪くするために引数リストが使用されています。

class SetProxy { 
public: 
    template <typename T> 
    typename std::enable_if<!std::is_convertible<T, long>::value 
          && !std::is_convertible<T, std::string>::value, void>::type 
    operator= (T const& value) { 
     std::cout << "template: " << value << "\n"; 
    } 
    void operator= (long value) { 
     std::cout << "long: " << value << "\n"; 
    } 
    void operator= (std::string value) { 
     std::cout << "std::string: '" << value << "'\n"; 
    } 
}; 
5

はなぜintlong過負荷によって処理されるのでしょうか?それらは同じタイプではなく、T = intのテンプレートはintに完全に一致し、longは完璧に一致しません。

あなたが解決しようとしている根本的な問題の詳細を教えてください。

+0

私は関数本体を追加しました。私は2つのTemplateString引数を取るSetValueを呼びたいと思います。 TemplateStringはconst char *とstd :: stringのコンストラクタを持っています。整数の場合は、SetIntValueを呼び出す必要があります。 – XTF

0

それがint、ここでテンプレートのバージョンと一致していることを予想外ではありません。

ただ、参考のために、ここでstd::enable_ifを使用して、私の意見では、より読みやすいバージョンです。テンプレートの引数のマッチングは、const int&に肯定的な一致を得て、それを過負荷解決に渡します。 intのほうが、longよりも、const int&が適しています。 int型のテンプレートバージョンを呼びたくない場合は、intの明示的なオーバーロードを追加することをお勧めします。

関連する問題