代码之家  ›  专栏  ›  技术社区  ›  Puppy

使用decltype()和SFINAE时出错

  •  3
  • Puppy  · 技术社区  · 14 年前

    作为对。。其他问题,我写了这段代码。

    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 );
    }
    

    has_apply<B> . decltype语句中t的替换失败,难道不意味着它只调用了另一个func吗?这不是斯芬娜的意思吗?

    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 );
    }
    
    2 回复  |  直到 12 年前
        1
  •  3
  •   usta    14 年前

    当替换函数模板的模板参数失败时,SFINAE适用,而不是类模板的模板参数,该类模板的模板参数将有问题的(非模板)函数作为成员,在您的情况下就是这样。

    修正后,你至少应该改变 decltype(T().apply<0u>(double())) decltype(T().template apply<0u>(double())) 因为 T() 表达式是依赖类型。原因是:当编译器第一次看到 T().apply<0u> T 但是,它应该如何解析令牌 apply < 之后 . ? 可能是成员模板,然后 < 会启动它的参数列表。奥托 应用 < 将被解析为“小于”运算符。有一个模棱两可的地方,现在编译器解决这个问题还为时过早。需要一种消除歧义的机制,程序员可以用它来告诉编译器 应用 .template (或 ->template ,或 ::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<>
    

    现在如果你把两个都拿走 .模板 从一开始 f() 定义,然后输出变成:

    no apply<>
    no apply<>
    

    表示替换失败 class A 因为它没有 名为的成员 应用

        2
  •  0
  •   Elias    14 年前

    很抱歉,作为一个回答,但评论似乎是为我散播。

     decltype( *(T*)0->template apply< 0u >( double() ) ) )
    

    这是有效的,因为它只出现在decltype中,在运行时并没有实际计算。另一个选择是

    T T_obj( void );
    

    然后使用

    decltype( T_obj().template apply< 0u >( double() ) ) )
    

    作为一个旁白,我记得读到斯特劳斯特罗普设计语言是因为他不想用错误的工具来完成工作。C++不是元语言编程的错误语言吗?

    虽然c++0x在很大程度上改进了一些东西,但这似乎不是重点。有没有像c++这样“接近金属”的语言可以提供更好的工具来编写在编译时生成代码的元代码?