4

用 GCC 编译我总是从下面的代码中得到错误。我相信这是一个编译器错误,但有人可能知道得更好。

#include <iostream>


template< class T > 
class has_apply { 

  typedef char yes[1];
  typedef char no[2];

  template< class U, U u > 
  struct binder {};

  template< class U, unsigned n >
  static yes& test( U*,
                        binder< void (U::*) ( const double& ),
                            &U::template apply< n >
                          >* = 0
                  );

  template< class U, unsigned n >
  static no& test( ... );

public:

  static const bool result =
         ( sizeof( yes ) == sizeof( test< T, 0u >( (T*)(0) ) ) );

}; 

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

};

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

4 回答 4

1

我无法声称理解为什么,但我能够通过不使用 U* 并拉出活页夹类型的声明来使您的代码工作:

template< class T > 
class has_apply { 

public:
  typedef char yes[1];
  typedef char no[2];

  template< class U, U u > 
  struct binder {};
  typedef binder< void (T::*)(const double&), &T::template apply<0u> > b;

  template < typename V, unsigned n >
  struct declare
  {
    typedef binder< void (V::*)(const double&), &V::template apply<n> > type;
  };

  template< typename U, unsigned n >
  static yes& test( typename declare<U,n>::type * );

  template< class U, unsigned n >
  static no& test( ... );


  static const bool result =
         ( sizeof( yes ) == sizeof( test< T, 0u >( 0 ) ) );

}; 

实际上,您可以通过从函数中删除无符号参数并将 0u 粘贴在“声明”中的 typedef 中来简化这一点。

同样,我无法解释为什么这个中间元函数是必要的,但它是必需的,并且以上在 MSVC++ 2010 中有效

于 2010-11-09T18:39:23.943 回答
1

Andy Venikov 在 [comp.lang.c++.moderated] 中的回答(我只是将出色的 google-foo 归功于(他他,我作弊)):

http://groups.google.com/group/comp.lang.c++.moderated/msg/93017cf706e08c9e

于 2010-11-09T20:07:22.153 回答
0

像诺亚一样,我不知道为什么。与 Noah 不同,我没有找到可行的解决方案,但调查了我设法使 MingW g++ 4.4.1 编译器崩溃的事情(即内部编译器错误)。这只是通过不一致地apply称为模板和非模板:

#include <iostream>


template< class T > 
class has_apply { 
  template< class U, U u > 
  struct binder {};

  template< class U >
  static double test(
    U*,
    binder<
        void (U::*) ( const double& ),
        //&U::template apply< 0 >
        &U::apply
      >* = 0
  );

public:

    static binder<
        void (T::*) ( const double& ),
        &T::template apply< 0 >
      >* dummy();

    static const bool result = sizeof( test( (T*)(0), dummy() ) );
};

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

};

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

对 g++ 的影响:

C:\test> g++ -std=c++98 y.cpp
y.cpp:在“has_apply”的实例化中:
y.cpp:38:从这里实例化
y.cpp:24: 内部编译器错误: in instantiate_type, at cp/class.c:6303
请提交完整的错误报告,
如果合适,使用预处理的源。
有关说明,请参阅。

C:\测试> _

呵呵...

PS:我很乐意将此作为“评论”发布,因为它不是“答案”。

于 2010-11-09T19:04:20.780 回答
0

这不是为什么它不起作用的答案。但是,通过网络进行研究,我找到了一些示例并最终得到了以下代码,这可能比我一直在尝试的更重要。

我试图检测一个特定的成员函数签名,但下面的代码超越并检测给定的调用是否可能,无论签名是什么。希望评论会有所帮助。

#include <iostream>

template< class T >
class has_apply {

  class yes { char c; };
  class no { yes c[2]; };

  struct mixin {
void apply( void );
  };

  // Calling derived::apply is only non-ambiguous if
  // T::apply does not exist, cf. 10.2.2.
  template< class U> struct derived : public U, public mixin {};

  // The following template will help on deduction based on this fact.
  // If U is type void (mixin::*) (void) then the template can be
  // instantiated with u = &derived< U >::apply if and only if T::apply
  // does not exist.
  template< class U, U u >
  class binder {};

  // Therefore, the following template function is only selected if there
  // is no T::apply:
  template< class U >
  static no  deduce( U, binder< void (mixin::*) (void), &derived< U >::apply >* = 0 );
  // Selected otherwise.
  static yes deduce( ... );

  // Provides an T object:
  static T T_obj( void );

public:

  static const bool result = ( sizeof( yes ) == sizeof( deduce( T_obj() ) ) );

};

namespace aux {

// Class to represent the void type as a "true" type.
class void_type {};

// deduce() some lines below will give us the right answer based on
// the return type of T::apply<>, but if it is void we cannot use a
// call to T::apply as an argument to deduce. In fact, the only
// function in c++ that can take such an argument is operator,() with
// its default behaviour and if an overload is not well formed it
// falls back to default.
template< class T >
T& operator,( const T&, void_type ) {};

// Copies the constness of T into U. This will be required in order
// to not get false positives when no const member is defined.
template< class T, class U >
struct copy_constness {
  typedef U result;
};
template< class T, class U >
struct copy_constness< const T, U > {
  typedef const U result;
};
}

template< class T >
class has_correct_apply{

  class yes { char c; };
  class no { yes c[2]; };

  // We assume has_apply< T >::result is true so the following class
  // is well declared. It is declared in a way such that a call to
  // derived::apply< n >() is always possible. This will be necessary
  // later.
  struct derived : public T {
using T::apply; // possible iff has_apply< T >::result == true
// This template function will be selected if the function call
// we wish is otherwise invalid.
template< unsigned n >
static no apply( ... );
  };

  // const_correct_derived will have the same constness than T.
  typedef typename aux::copy_constness< T, derived >::result const_correct_derived;
  // Provides a const correct derived object.
  static const_correct_derived derived_obj( void );

  // Only possible call was derived::apply: call is impossible for signature:
  static no  deduce( no );
  // Since te returned value of it will most likely  be
  // ignored in our code (void must be always [almost, see next]
  // ignored anyway), we return yes from this:
  static yes deduce( ... );
  // As we noticed, an overload of operator,() may make an exact match necessary.
  // If we want this we could simply have used "no" instead of "yes" above and:
//   static no  deduce( aux::void_type );


public:

  static const bool result = ( sizeof( yes ) == sizeof( deduce(
( derived_obj().template apply< 0u >( 0.0 ), aux::void_type() )
  ) ) );

  // Note: Inteestingly enough, GCC does not detect an private subclass default
  // constructor and so const_correct_derived() could be used instead of
  // having a function derived_obj(), but I do not know if this behavoiur is
  // standard or not.

};


struct C {
  template< unsigned n >
  int apply( double, unsigned m = 10 ) const;
private:
  C();
};

struct D {
  template< unsigned n >
  int apply( const double& );
private:
  D();
};

struct E : public C {
};

struct Without{};

#include "mp.h"

int main()
{
  std::cout << has_apply< E >::result << '\n';
  std::cout << has_correct_apply< const E >::result << '\n';
  std::cout << has_correct_apply< const D >::result << '\n';
  std::cout << has_correct_apply< D >::result << '\n';
//   E e;

  return( 0 );
}
于 2010-11-13T15:57:06.373 回答