olp*_*lpa 9 c++ templates c++11
下面的代码正确检查类型T是否有方法sort.但是当我修改标记(*)为更改decltype(&U::sort,...)为的行decltype(U::sort,...)(符号&被删除)时,代码始终返回false.
为什么?
为什么这个名字本身还不够?这&是什么意思?
#include <iostream>
#include <type_traits>
template <typename T>
class has_sort {
  template <typename U>
  static auto check(bool) -> decltype(&U::sort, std::true_type()); // (*)
  template <typename U>
  static std::false_type check(...);
public:
  using type = decltype(check<T>(true));
  static bool const value = type::value;
};
int main() {
  struct Foo { void sort(); };
  struct Foo2 { void sort2(); };
  std::cout << "Foo: " << has_sort<Foo>::value << std::endl;
  std::cout << "Foo2: " << has_sort<Foo2>::value << std::endl;
  std::cout << "int: " << has_sort<int>::value << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
    答案很简单:如果没有成员函数的地址,就不能使用&.你不能自己尝试:
auto fun = Foo::sort; // error
Run Code Online (Sandbox Code Playgroud)
标准要求必须使用成员函数指针&,因为没有它,语法将是不明确的.想象一下,在模板中:
template<typename T>
void test() {
    T::test2; // is it a member function pointer or static data member?
}
Run Code Online (Sandbox Code Playgroud)
因此,sfinae检查是正确的:没有&,如果类型T将具有名为的静态数据成员,则检查将为true sort.
但是,你可以通过这个技巧绕过这个限制,虽然它是出于演示的目的,我不建议你这样做:
struct Foo {
    void sortImpl();
    static constexpr auto sort = &Foo::sortImpl;
};
Run Code Online (Sandbox Code Playgroud)
然后检查名为的静态数据成员sort是否正确,并且sort将是一个函数指针.
通过使用,&U::foo您通常会检查类型是否U包含成员方法(静态或非静态)或数据成员(静态或非静态)。
因此,它将匹配以下所有类型(以及其他类型,如果您还考虑说明符):
struct Foo { void sort(); };struct Foo { static void sort(); };struct Foo { int sort; };struct Foo { static int sort; };另一方面,U::foo不能用于检测成员方法(即使在某些情况下您仍然可以使用它来检测数据成员)。
无论如何,因为您也可以template <typename U> static std::false_type check(...);使用,当您尝试检测sort成员方法时,由于 sfinae 规则,上述函数专门化期间的错误将被默默地丢弃,并且该错误将被拾取。
如果您想更严格并要求sort是一个函数(无论是否静态),您应该包含utility标头并使用std:: declval它。这样,就不再需要 & 符号了:
template <typename U>
static auto check(bool) -> decltype(std::declval<U>().sort(), std::true_type()); // (*)
Run Code Online (Sandbox Code Playgroud)
这样,sort就不会再检测到数据成员名称。
int如果我可以给你一个建议,你可以通过使用/char重载和函数来简化一些事情constexpr。
举个例子:
template <typename T>
class has_sort {
    template <typename U>
    constexpr static auto check(int) -> decltype(std::declval<U>().sort(), std::true_type()) { return {}; }
    template <typename U>
    constexpr static std::false_type check(char) { return {}; }
public:
    static constexpr bool value = check<T>(0);
};
Run Code Online (Sandbox Code Playgroud)
如果可以使用 C++14,模板变量会更加紧凑:
template<typename T, typename = void>
constexpr bool has_sort = false;
template<typename T>
constexpr bool has_sort<T, decltype(std::declval<T>().sort(), void())> = true;
Run Code Online (Sandbox Code Playgroud)
您可以在示例中使用它,如下所示:
std::cout << "Foo: " << has_sort<Foo> << std::endl;
Run Code Online (Sandbox Code Playgroud)