【问题标题】:std::declval<T>(), SFINAE and deleted constructorstd::declval<T>()、SFINAE 和删除的构造函数
【发布时间】:2017-11-06 10:27:16
【问题描述】:

在 C++11 中使用 SFINAE 进行方法检测,我写了这个小运行示例:

#include <type_traits>

struct Foo
{
  Foo();// = delete;
  Foo(int);

  void my_method();
};

template <typename T, typename ENABLE = void>
struct Detect_My_Method 
   : std::false_type
{
};

template <typename T>
struct Detect_My_Method<T, decltype(T().my_method())> 
   : std::true_type
{
};

int main()
{
  static_assert(!Detect_My_Method<double>::value, "");
  static_assert(Detect_My_Method<Foo>::value, "");
}

按预期工作。

但是,如果我删除 Foo 的空构造函数:

struct Foo
{
  Foo() = delete;
  Foo(int);

  void my_method();
};

示例不再不起作用,我收到以下错误消息:

g++ -std=c++11 declVal.cpp 
declVal.cpp: In function ‘int main()’:
declVal.cpp:33:3: error: static assertion failed
   static_assert(Detect_My_Method<Foo>::value, "");

问题:解释以及如何解决?

【问题讨论】:

    标签: c++ c++11 metaprogramming sfinae


    【解决方案1】:

    当空的构造函数被删除构造:

    decltype(Foo().my_method());
    

    不再有效,编译器立即抱怨

    error: use of deleted function ‘Foo::Foo()’
    

    一种解决方案是使用std::decval&lt;T&gt;()

    将任何类型 T 转换为引用类型,使其可以使用 decltype 表达式中的成员函数无需去 通过构造函数。

    因此替换:

    template <typename T>
    struct Detect_My_Method<T, decltype(T().my_method())> 
       : std::true_type
    {
    };
    

    通过

    template <typename T>
    struct Detect_My_Method<T, decltype(std::declval<T>().my_method())> 
       : std::true_type
    {
    };
    

    解决问题。

    吸取的教训:

    decltype(Foo().my_method());                // invalid
    decltype(std::declval<Foo>().my_method());  // fine
    

    不等价。

    【讨论】:

      【解决方案2】:

      此外,还有另一种定义测试的方法,它既不需要对象的引用或指针,也不需要函数的特定签名:

      template<class T>
      typename std::is_member_function_pointer<decltype(&T::my_method)>::type test_member_function_my_method(int);
      
      template<class T>
      std::false_type test_member_function_my_method(...);
      
      template<class T>
      using has_member_function_my_method = decltype(test_member_function_my_method<T>(0));
      

      用法:

      static_assert(!has_member_function_my_method<double>::value, "");
      static_assert(has_member_function_my_method<Foo>::value, "");
      

      【讨论】:

      • 这不是完全等效的,因为declval 方法可以检测函数对象。如果T 有一个成员变量my_method 和operator(),它将检测为有效。这可能是可取的,也可能不是可取的,或者您可能关心也可能不关心。
      • @贾斯汀你是对的。它也不处理重载函数,因为这里不涉及调用参数。
      猜你喜欢
      • 1970-01-01
      • 2018-06-04
      • 1970-01-01
      • 2018-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-22
      相关资源
      最近更新 更多