以下代码正确检查类型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;
}
答案 0 :(得分:5)
答案很简单:如果没有&
,您就无法获取成员函数的地址。你不能自己尝试:
auto fun = Foo::sort; // error
标准要求成员函数指针必须与&
一起使用,因为没有它,语法将是不明确的。想象一下,在模板中:
template<typename T>
void test() {
T::test2; // is it a member function pointer or static data member?
}
所以sfinae检查是正确的:没有&
,如果类型T
具有名为sort
的静态数据成员,则检查将为真。
然而,你可以通过这个技巧绕过这个限制,但是,它是出于演示的目的,我不建议你这样做:
struct Foo {
void sortImpl();
static constexpr auto sort = &Foo::sortImpl;
};
然后检查名为sort
的静态数据成员是否正确,sort
将是函数指针。
答案 1 :(得分:3)
通过使用&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()); // (*)
这样,数据成员名称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);
};
如果你可以使用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;
您可以在示例中使用它,如下所示:
std::cout << "Foo: " << has_sort<Foo> << std::endl;