1

Does anyone know how to detect a constructor with one argument? For example, this struct should have a negative result:

struct MyStruct
{
  MyStruct( int x, int x2 ) : y( x ) {}
  int y;
};

I have here a nice SFINAE check to see if a class or struct as a constructor with a specific number of arguments. Here's the one for argument count of 3:

template <typename T>
struct HasCtor3Args
{
  struct Any { template <typename U> operator U( void ); };

  template <typename U>
  static int32 SFINAE( decltype( U( Any( ), Any( ), Any( ) ) ) * );

  template <typename U>
  static int8 SFINAE( ... );

  static const bool value = sizeof( SFINAE<T>( NULL ) ) == sizeof( int32 );
};

This seems to work just fine, as the Any struct can convert to whatever types the parameters ought to be. However the issue is when trying to detect a constructor with just one argument. The SFINAE check seems to always return true due to defaulting Any to the same type as T thus detecting a copy constructor.

Edit and Update: I've made a few attempts, none seem to be a go... This was the closest I can get, but doesn't work as it always returns true. The idea was to try and get the copy constructor to resolve instead of the first "catch all" call:

template <typename T>
struct HasCtor1Args
{
  struct Any
  {
    template <typename U>
    operator U( ) const;
  };

  template <typename U>
  static int32 SFINAE( decltype( U( Any( ) ) ) * );

  // Try to catch the copy ctor here
  T MakeT( void );
  template <typename U>
  static int8 SFINAE( decltype( U( MakeT( ) ) ) * );

  template <typename U>
  static int8 SFINAE( ... );

  static const bool value = sizeof( SFINAE<T>( NULL ) ) == sizeof( int32 );
};

I also tried using the explicit keyword, along with the = delete feature for C++11, then realized the compiler I need to use (Microsoft's) does not allow this. I also tried using std::enable_if on the conversion type U, although I ran into the error that function template parameters cannot be defaulted.

4

1 回答 1

2

尽管 nm 的批评仍然成立,但这里有一个版本来检测只有一个1 参数非复制、非移动 ctor 的类型。它使用 SFINAE 来限制Any.

注意:具有默认参数的其他 ctor 会导致歧义(例如my_type(int, double=0);,这是一个非常有限的解决方案。

#include <cstdint>
#include <type_traits>

template <typename T>
struct HasCtor1Args
{
    struct Any
    {
      template
      <
        typename U, typename SFINAE =
          typename std::enable_if< false == std::is_same<U,T>::value, U >::type
      >
      operator U() const;
    };

    template <typename U>
    static int32_t SFINAE( decltype( U( Any( ) ) ) * );

    template <typename U>
    static int8_t SFINAE( ... );

    static const bool value = sizeof( SFINAE<T>( nullptr ) ) == sizeof( int32_t );
};


struct my_type
{
    my_type(int);
    my_type(my_type const&);
};

int main()
{
    static_assert(HasCtor1Args<my_type> :: value, "epic fail");
}
于 2013-04-22T16:42:23.110 回答