【问题标题】:SFINAE - Detect constructor with one argumentSFINAE - 用一个参数检测构造函数
【发布时间】:2013-04-21 23:52:47
【问题描述】:

有谁知道如何检测带有一个参数的构造函数?例如,这个结构应该有一个否定的结果:

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,从而检测到复制构造函数。

编辑和更新: 我做了一些尝试,似乎都没有成功......这是我能得到的最接近的结果,但它不起作用,因为它总是返回 true。这个想法是尝试让复制构造函数解析而不是第一个“catch all”调用:

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

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

【问题讨论】:

  • 哦,还有std::is_constructible
  • 由于某种原因,它在转换运算符明确时起作用:template &lt; typename U &gt; explicit operator U() const;。我不得不在标准中查找这个,但这可能是 g++ 4.8 中的一个错误。
  • 嗯,我不认为使用这样的显式方法可以在微软的编译器上工作。
  • 如果有两个单参数构造函数,替换将失败。我认为没有办法解决它。
  • 好吧,我将其解释为“只接受一个参数”,或者等效地,“只有一个参数”;)

标签: c++ templates metaprogramming sfinae


【解决方案1】:

虽然 n.m. 的批评仍然成立,但这里有一个版本来检测具有 只有一个 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");
}

【讨论】:

  • 哦,等等,nvm...参数类型将被推断为Any,我想。默认参数也是如此。不过,template&lt;class T&gt; C(Something&lt;T&gt;) 会失败。
  • 我不明白为什么它会因此而失败。 T 简单地变成了 Any 类型。
  • @Johannes:是的,请看我上面的新评论。
  • .... 但是我们有同样的错误想法,Xeo :D 不过,我认为默认参数问题仍然存在。
  • 您可以使用参数类型绝对接受 any 类型的函数重载测试函数(但不完全是 any 类型,因此需要用户定义的转换)。如果调用现在以歧义结束(通过 sfinae 检测到它),则 T 有一个或多个单参数接受 ctor)。这将很好地处理歧义(没有双关语)。
猜你喜欢
  • 2018-08-28
  • 2018-06-04
  • 2017-01-14
  • 1970-01-01
  • 2015-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多