3

为了回应 .. 某处的其他问题,我编写了这段代码。

struct no_type{};
template<typename T> struct has_apply {
    static decltype(T().apply<0u>(double())) func( T* ptr );
    static no_type func( ... );
    static const bool result = !std::is_same<no_type, decltype(func(nullptr))>::value;
};

class A {
public:
    template< unsigned n >
    void apply( const double& );

};
class B {
};

int main()
{
  std::cout << std::boolalpha << has_apply< A >::result << '\n';
  std::cout << std::boolalpha << has_apply< B >::result << '\n';
  std::cin.get();
  return( 0 );
}

现在在我看来,如果 T 提供了一个接受双右值和模板参数文字的非静态成员函数“apply”,则结果应该为真,否则为假。但是,在编译时,给出的示例实际上无法为 B 类编译has_apply<B>。在 decltype 语句中替换 T 失败的事实不应该意味着它只是调用另一个函数吗?这不是 SFINAE 的重点吗?

以最荒谬、最无意义的方式解决:

struct no_type{};
template<typename T> struct has_apply {
    template<typename U> static decltype(U().apply<0u>(double())) func( U* );
    template<typename U> static no_type func( ... );
    static const bool result = !std::is_same<no_type, decltype(func<T>(nullptr))>::value;
};

class A {
public:
    template< unsigned n >
    void apply( const double& );

};
class B {
};

int main()
{
  std::cout << std::boolalpha << has_apply< A >::result << '\n';
  std::cout << std::boolalpha << has_apply< B >::result << '\n';
  std::cin.get();
  return( 0 );
}
4

1 回答 1

3

当函数模板的模板参数替换失败时,SFINAE 适用,而不适用于将(非模板)函数作为成员的类模板的模板参数,就像您的情况一样。

修复后,您至少应该更改decltype(T().apply<0u>(double()))为,decltype(T().template apply<0u>(double()))因为T()表达式是依赖类型。这样做的原因是:当编译器第一次看到 时T().apply<0u>,它还不知道任何事情T,那么它应该如何解析标记apply<之后的.apply可能是一个成员模板,然后<会为其启动参数列表。OTOHapply可能改为非模板成员(例如数据成员),然后<将被解析为“小于”运算符。有一个模棱两可的地方,编译器现在解决这个问题还为时过早。程序员需要一种消歧机制来告诉编译器什么apply预计是:模板与否。这里来了.template(or ->template, or ::template) 构造来拯救:如果它存在,编译器知道它应该是一个模板成员,否则如果它不存在那么编译器知道该成员不应该是一个模板。

最后,这是我创建的一个示例,它可以正常工作并在 g++ 4.5.0 上产生所需的结果-std=c++0x

#include <iostream>

template < class T >
decltype( T().template apply< 0u >( double() ) ) f( T &t )
{
    return t.template apply< 0u >( 5. );
}

const char *f( ... )
{
    return "no apply<>";
}

class A {
public:
    template < unsigned >
    int apply( double d )
    {
        return d + 10.;
    }
};

class B {};

int main()
{
    A a;
    std::cout << f( a ) << std::endl;
    B b;
    std::cout << f( b ) << std::endl;
}

输出是:

15
no apply<>

现在,如果您.template从第一个f()定义中删除两者,则输出变为:

no apply<>
no apply<>

这表示替换失败,class A因为它没有任何名为的非模板成员apply。SFINAE 在行动!

于 2010-11-09T18:26:39.307 回答