函数与函数名之间有一个&符号
SFINAE with ampersand before a function vs its name
下面的代码正确地检查类型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;
}
答案很简单:如果没有&
,就不能获取成员函数的地址。你不能自己尝试:
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
将是一个函数指针
通过使用&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;
- 用符号版本替换对函数的所有调用
- C++模板函数,用于比较任何无符号整数和有符号整数
- 为什么 gcc 和 clang 为函数模板的实例化生成不同的符号名称?
- 为函数定义符号不明确的指针参数
- 在函数中返回无符号字符数组,但不返回指针
- 如何返回实际值(在我的例子中是无符号字符数组)而不是来自 C++ 函数的指针?
- MacOS 上的 Xcode 11 项目不在一个函数中使用 sin 和 cos:未定义的符号"___sincosf_stret"
- 仅在 MacOS 上析构函数的未定义符号
- clang:使用 O3 导出隐式实例化函数的符号
- 函数 _main (OPENGL C++) 中引用的未解析的外部符号 ________
- 在函数内初始化无符号字符指针将返回空指针
- 如何识别符号表中的符号是我'application'函数
- dll导出函数的函数符号来自静态链接库
- 调用弱函数符号和强函数符号?
- Glew - 与 GLFW 配对时 gl- 函数符号上出现链接错误
- 链接错误:找不到__thiscall函数符号,但定义了__cdecl函数符号
- 如何从通用函数符号计算或指定COFF符号表的"value"?
- 链接两个具有相同函数签名的强函数符号的结果使用 G++ 以及原因
- 在抽象类中使用shared_ptr时,如何在nm或objdump中找到函数符号
- 类析构函数符号出了什么问题?在vc++中