2010-08-08 20 views
5

'name' adında bir üyeye sahip bir sınıfı ayırt etmek için SFINAE kullanmaya çalışıyorum. Standart model gibi görünen şeyleri ayarlıyorum ama çalışmıyor - 'başarısız' ikamesini sessizce göz ardı etmek yerine, derleyici bir hata üretir.SFINAE: Bazı hatalar diğerlerinden daha eşit midir?

Bazı şablon değiştirme kurallarına karşı koştuğumdan eminim, biri hangisini açıklayabilirse minnettar olurum.

Bu, soyulmuş bir örnektir. Gcc kullanıyorum:

template <typename U> string test(char(*)[sizeof(U::name)] = 0) { return "has name!"; } 
template <typename U> string test(...) { return "no name"; } 

struct HasName { string name; } 
struct NoName {} 

cout << "HasName: " << test<HasName>(0) << endl; //fine 
cout << "NoName: " << test<NoName>(0) << endl; //compiler errors: 

//error: size of array has non-integral type `<type error>' 
//error: `name' is not a member of `NoName' 
+0

Hangi derleyiciyi kullanıyorsunuz? g ++ 4.4.3 bu kodu kabul eder ve '-Wall -Wextra -pedantic' ile bile herhangi bir diyagnostik yaymaz. –

+3

@Tyler: "struct" tanımlarından sonra eksik yarı-colonslar için tanılama yapmıyor mu? ;-) –

+0

oops :-); Eminim ki (dikkatsiz yazarak mazeret) –

cevap

1

aşağıdaki (Michael söylediği gibi olsa, bu malzemeyi diğer derleyicilerde istediğiniz sonucu vermez) geçerli görünür:

#include <string> 
#include <iostream> 
using namespace std; 

template <typename U> string test(char(*)[sizeof(U::name)] = 0) { return "has name!"; } 
template <typename U> string test(...) { return "no name"; } 

struct HasName { static string name; }; 
struct NoName { }; 

int main() { 
    cout << "HasName: " << test<HasName>(0) << endl; 
    cout << "NoName: " << test<NoName>(0) << endl; 
} 

Çıktı:

HasName: has name! 
NoName: no name 

gcc (GCC) 4.3.4 20.090.804 (serbest bırakma) 1

Comeau da kodu kabul .

+0

Bazı ek veri noktaları: MSVC 9/10 da kodu ('isim' üyesinde 'statik' olmasa bile) kabul eder, ancak beklenen çıktıyı üretmez. MinGW (GCC 3.4.5), üyeyi "statik" olan veya olmayan olarak derlemez. –

+0

@Michael: belki de "iyi görünüyor" demeliyim. "Comeau kabul eder" kelimesini "geçerli C++" ile eşanlamlı olarak kabul ediyorum, ancak bunun sadece çok iyi bir yaklaşım olduğunu kabul ediyorum :-) –

+0

Oh ve Comeau kodu kabul ederken MSVC ile aynı çıktıyı üretiyor. her iki "test <>()') çağrısında "isimsiz" yazıyor. –

0

İşte bu bir girişim var:

// Tested on Microsoft (R) C/C++ Optimizing Compiler Version 15.00.30729.01 
template<typename T> 
class TypeHasName 
{ 
private: 
    typedef char (&YesType)[2]; 
    typedef char (&NoType)[1]; 

    struct Base { int name; }; 
    struct Derived : T, Base { Derived(); }; 

    template<typename U, U> struct Dummy; 

    template<typename U> 
    static YesType Test(...); 

    template<typename U> 
    static NoType Test(Dummy<int Base::*, &U::name>*); 

public: 
    enum { Value = (sizeof(Test<Derived>(0)) == sizeof(YesType)) }; 
}; 

#include <string> 
#include <iostream> 

struct HasName { std::string name; }; 
struct NoName {}; 

int main() 
{ 
    std::cout << "HasName: " << TypeHasName<HasName>::Value << std::endl; 
    std::cout << "NoName: " << TypeHasName<NoName>::Value << std::endl; 
    return 0; 
} 

fikri Tname adında bir değişken varsa, o zaman Derived iki name değişkenler (T itibaren bir ve Base itibaren bir) sahip olmasıdır. T bir name değişken bildirmezse, Derived yalnızca Base'dan birine sahip olacaktır.

iki name değişkenler, daha sonra ikinci Test() aşırı ekspresyon &U::name belirsiz olacaktır ve SFINAE aşırı kümesinden bu işlev kaldırmak gerekir Derived varsa.

İlgili konular