Это не ответ на вопрос, почему это не работает.Тем не менее, просматривая в Интернете, я нашел несколько примеров и в итоге получил следующий код, который может быть даже более точным, чем то, что я пытался.сигнатура функции-члена, но приведенный ниже код выходит за рамки и определяет, возможен ли данный вызов, независимо от того, что является сигнатурой.Надеюсь, что комментарии будут полезны.
#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 );
}