SFINAE - 使用一个参数检测构造函数

时间:2013-04-21 23:52:48

标签: c++ templates metaprogramming sfinae

有谁知道如何使用一个参数检测构造函数?例如,此结构应该具有否定结果:

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

我在这里有一个很好的SFINAE检查,看看一个类或结构是否是一个具有特定数量参数的构造函数。这是参数计数为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 );
};

这似乎工作正常,因为Any结构可以转换为参数应该是的任何类型。但问题是在尝试仅使用一个参数检测构造函数时。由于将Any默认为与T相同的类型,SFINAE检查似乎总是返回true,从而检测到复制构造函数。

修改和更新: 我做过几次尝试,似乎没有一次尝试...这是我能得到的最接近的,但不起作用,因为它总是返回真实。我的想法是尝试解决复制构造函数而不是第一个“全部捕获”调用:

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

我也尝试使用explicit关键字,以及C ++ 11的= delete功能,然后意识到我需要使用的编译器(微软)不允许这样做。我也尝试在转换类型U上使用std :: enable_if,尽管我遇到了函数模板参数无法默认的错误。

1 个答案:

答案 0 :(得分:2)

虽然上午的批评仍然存在,但这里有一个版本来检测只有一个 1参数非复制,非移动ctor的类型。它使用SFINAE来限制Any的转换。

注意:带有默认参数的其他ctors会导致歧义(例如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");
}