指针指向成员函数的SFINAE类型特征失败



我正在练习SFINAE,并希望实现一个类型特征,以便检查给定的类T是否包含方法print()。我有以下两种变体:

// (1)
template <typename T, typename = int>
struct has_print_method : std::false_type {};
template <typename T>
struct has_print_method<T, decltype(&T::print, 0)> : std::true_type {};
template <typename T>
const bool has_print_method_v = has_print_method<T>::value;
// (2)
template <typename T>
struct has_print_method{
template <typename U, typename = void> struct helper : std::false_type{};
template <typename U> struct helper<U, decltype(&U::print)> : std::true_type{};
static const bool value = helper<T, void (T::*)() const>::value;
};
template <typename T>
const bool has_print_method_v = has_print_method<T>::value;

(1( 仅检查成员方法CCD_ 3的存在而忽略该成员方法的签名。而(2(检查方法的签名,即它需要一个成员方法void print() const

我通过测试这两种变体

#include <iostream>
#include <type_traits>
// Simple Class A
struct A{
int a;
public:
void print() const{}
};
// (1) or (2) here
template<typename T, std::enable_if_t<has_print_method_v<T>, bool> = true>
void print(T t) {
t.print();
}
void print(double x){
std::cout << x << 'n';
}

int main() {
A a;
print(a);
print(1.0);  // (*)
return 0;
}

使用类型trait(1(并使用clang 12.0和std=c++17标志进行编译可以按预期工作。然而,使用(2(,我获得

<source>:28:50: error: member pointer refers into non-class type 'double'
static const bool value = helper<T, void (T::*)() const>::value;
^
<source>:32:33: note: in instantiation of template class 'has_print_method<double>' requested here
const bool has_print_method_v = has_print_method<T>::value;
^
<source>:34:39: note: in instantiation of variable template specialization 'has_print_method_v<double>' requested here
template<typename T, std::enable_if_t<has_print_method_v<T>, bool> = true>
^
<source>:35:6: note: while substituting prior template arguments into non-type template parameter [with T = double]
void print(T t) {
^~~~~~~~~~~~
<source>:47:5: note: while substituting deduced template arguments into function template 'print' [with T = double, $1 = (no value)]
print(1.0);
^
1 error generated.

我在这里错过了什么?你可以在godbolt上找到这个例子。编辑:嗯,我刚刚注意到,这两个版本都是用gcc11.1编译的,没有错误。奇怪的

首先,根据您的错误消息和我自己的测试判断,我认为您的意思是类型特征(1(有效,而(2(无效。在此基础上,这里有一个特性(1(的版本,它测试匹配的函数签名:

template <typename T, typename = int>
struct has_print_method : std::false_type {};
template <typename T>
struct has_print_method<T, decltype(&T::print, 0)> : std::is_same <decltype(&T::print), void (T::*)() const> {};
template <typename T>
const bool has_print_method_v = has_print_method<T>::value;

现场演示

最新更新