C++ SFINAE:有些失败比其他失败更平等?

C++ SFINAE:有些失败比其他失败更平等?,c++,templates,template-specialization,sfinae,C++,Templates,Template Specialization,Sfinae,我试图用它来区分一个类,它有一个名为“name”的成员。我在标准模式中设置了一些东西,但它不起作用——编译器不是默默地忽略“失败”的替换,而是生成一个错误 我确信我遇到了一些模板替换规则,如果有人能解释一下是哪一个,我将不胜感激 这是一个简单的例子。我正在使用gcc: template <typename U> string test( char(*)[sizeof(U::name)] = 0 ) { return "has name!"; } template <type

我试图用它来区分一个类,它有一个名为“name”的成员。我在标准模式中设置了一些东西,但它不起作用——编译器不是默默地忽略“失败”的替换,而是生成一个错误

我确信我遇到了一些模板替换规则,如果有人能解释一下是哪一个,我将不胜感激

这是一个简单的例子。我正在使用gcc:

 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'
模板字符串测试(char(*)[sizeof(U::name)]=0){return“has name!”;}
模板字符串测试(…){返回“无名称”;}
结构HasName{string name;}
结构非名称{}

cout以下内容似乎是有效的(尽管正如Michael所说,它不一定给出您在其他编译器上想要的结果):

gcc(gcc)4.3.4 20090804(发行版)1


也接受代码。

下面是一个尝试:

// 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;
}
//在Microsoft(R)C/C++优化编译器版本15.00.30729.01上测试
模板
类TypeHasName
{
私人:
typedef char(&YesType)[2];
typedef字符(&NoType)[1];
结构基{int name;};
派生结构:T,基{Derived();};
模板结构虚拟;
模板
静态叶氏试验(…);
模板
静态不定型试验(假人*);
公众:
枚举{Value=(sizeof(Test(0))==sizeof(YesType))};
};
#包括
#包括
结构HasName{std::string name;};
结构非名称{};
int main()
{  

std::cout您使用的是哪种编译器?g++4.4.3接受此代码,即使使用
-Wall-Wextra-pedantic
@Tyler:它甚至不会对
结构定义之后缺少的分号发出诊断?;-)oops:-);我肯定会发出诊断(请原谅粗心的键入)一些额外的数据点:MSVC 9/10也接受代码(即使没有
名称
成员上的
静态
),但不会产生预期的输出。MinGW(GCC 3.4.5)在成员为
静态
或不为
静态
的情况下都不会编译它@Michael:那么也许我应该说“看起来很好”。我通常会“Comeau接受它”是“它是有效的C++”的同义词,但我认识到这只是一个非常好的近似值:-)哦,虽然Comeau接受代码,但它产生与MSVC相同的输出(也就是说,它对
test()
的两个调用都说“没有名字”)@Michael:另外,我有一种模糊的感觉,C++0x中允许使用
class::member
语法获取非静态数据成员的
sizeof
。因此,如果编译器不使用
static
,而接受它,@Steve g++不使用
-std=C++98-pedantic
而接受它,也就不足为奇了。不确定g是否使用
-std=C++98-pedantic++这里出了什么问题。
HasName: has name!
NoName: no name
// 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;
}