2014-10-30 19 views
6

Aşağıdaki şablonu nesne var:Şablon türlerine bağlı olarak kurucuları etkinleştirmek veya devre dışı bırakmak için std :: enable_if öğesini nasıl kullanırım?

template< typename type_1, typename type_2 > struct result 
{ 
    // I want to enable these two constructors only if type_1 != type_2 
    result(type_1 f) : foo{f} {} 
    result(type_2 b) : bar{b} {} 

    // I want to enable this constructor only if type_1 == type_2 
    result(type_1 f, type_2 b) : foo{f}, bar{b} {} 

    // Other member functions removed. 

    type_1 foo; 
    type_2 bar; 
}; 

nasıl gerektiği gibi etkinleştirmek veya devre dışı bırakmak için kurucular std::enable_if kullanırım?

örn:

Bu seferki olurdu sadece ilk iki kurucular:

result<string,int> // type_1 != type_2 

Bu seferki sadece üçüncü yapıcı olurdu:

result<int,int> // type_1 == type_2 

cevap

5

This çalışma görünüyor, ama ben

En uygun yol olduğundan emin değilsiniz. yapıcıya varsayılan değerlerle yeni şablon parametreleri Ayrıca okumak

#include <type_traits> 

template< typename type_1, typename type_2 > 
struct result 
{ 
    // I want to enable these two constructors only if type_1 != type_2 
    template<typename T1 = type_1, typename T2 = type_2> 
    result(type_1 f, 
      typename std::enable_if<!std::is_same<T1, T2>::value>::type * = nullptr) 
     : foo{f} {} 
    template<typename T1 = type_1, typename T2 = type_2> 
    result(type_2 b, 
      typename std::enable_if<!std::is_same<T1, T2>::value, int >::type * = nullptr) 
     : bar{b} {}          /*  ^^^ need this to avoid duplicated signature error with above one*/ 

    // I want to enable this constructor only if type_1 == type_2 
    template<typename T1 = type_1, typename T2 = type_2> 
    result(type_1 f, type_2 b, 
      typename std::enable_if<std::is_same<T1, T2>::value>::type * = nullptr) 
     : foo{f}, bar{b} {} 

    type_1 foo; 
    type_2 bar; 
}; 

int main() 
{ 
    result<int, double> r(1); 
    result<int, double> r2(1.0); 

    result<int, int> r3(1, 2); 

    // disbaled 
    //result<int, double> r4(1, 2.0); 
    //result<int, int> r5(1); 
} 

SFINAE

etkinleştirmek için: Select class constructor using enable_if

4

birincil şablon mistmatched türleri için bir uzmanlık olarak hizmet edebilir. Bu @ BryanChen cevabı benzer

template <typename type_1, typename type_2> 
struct result 
{ 
    result(type_1 f) : foo{f} {} 
    result(type_2 b) : bar{b} {} 

    type_1 foo; 
    type_2 bar; 
}; 

template <typename type> 
struct result<type, type> 
{ 
    result(type f, type b) : foo{f}, bar{b} {} 

    type foo; 
    type bar; 
}; 
+1

Sorunu "result" nesnesinin gösterilmeyen üye işlevleri grubuna sahip olduğundan bahsetmiştim, bu nedenle uzmanlaşma çok fazla kod çoğaltmasına yol açacaktır. –

+1

@DrTwox Sonra Bryan'ın çözümünü kullanın. Maalesef şu anda herhangi bir alternatifin farkında değilim. – 0x499602D2

+1

@DrTwox Tüm ortak kodları bir sınıfa ve diğer koddaki özel koda koyarak bu tekrarı önlemek için kalıtım kullanabilirsiniz. Bu yaygın bir çözümdür. Durumunuza bağlı olarak, CRTP de dahil olmak üzere birkaç şekilde yapabilirsiniz. Örneğin, bir temel sınıftaki kuruculara (ve veri üyelerine) sahip olabilirsiniz, bunlar her iki durumda da (aynı veya değil) uzmanlaşabilir ve türetilmiş sınıfınızda kalıtsal kurucular (C++ 11) kullanabilirsiniz. Ya da tam tersi, temel sınıftaki tüm ortak kodlarla ince bir türetilmiş sınıfı uzmanlaşın. –

2

fakat temizleyici IMO :) Sen belirsizlik çözünürlüğünü artırmak için miras kullanabilir ve yapıcı şablon argümanları enable_if s taşıyın: eşleşen türleri için kısmen uzmanlaşabilir.

#include <iostream> 
#include <string> 
#include <type_traits> 

using namespace std; 

template <int N> 
class Disambiguator; 

template<> 
class Disambiguator<0>{}; 

template <int N> 
class Disambiguator : public Disambiguator<N-1>{}; 

using Disambiguate = Disambiguator<100>; 

template< typename type_1, typename type_2 > struct result 
{ 
    template <typename T, typename U> 
    using IsSame = typename enable_if<is_same<T, U>::value>::type; 

    template <typename T, typename U> 
    using IsNotSame = typename enable_if<!is_same<T, U>::value>::type; 

    template <typename T = type_1, typename U = type_2, typename = IsNotSame<T,U>> 
    result(type_1 f, Disambiguator<0>) : foo{f} {cout<<"NotSameType"<<endl;} 

    template <typename T = type_1, typename U = type_2, typename = IsNotSame<T,U>> 
    result(type_2 b, Disambiguator<1>) : bar{b} {cout<<"NotSameType"<<endl;} 

    // I want to enable this constructor only if type_1 == type_2 
    template <typename T = type_1, typename U = type_2, typename = IsSame<T,U>> 
    result(type_1 f, type_2 b) : foo{f}, bar{b} {cout<<"SameType"<<endl;} 

    // Other member functions removed. 

    type_1 foo; 
    type_2 bar; 
}; 


int main() 
{ 
    result<float, int> c(1.0, Disambiguate{}); 
    result<float, int> i(0, Disambiguate{}); 

    result<int, int> j(0, 0); 

    result<string, int> s("abc", Disambiguate{}); 
    result<string, int> si(0, Disambiguate{}); 

    return 0; 
} 

DÜZENLEME: Xeo en aşırı yük çözünürlük fikri here @ okuyabilir. Yukarıdaki kodda kullandığım buydu.

İlgili konular