我在这里找到了几个问题,这些问题涉及检查给定类型是否存在成员函数,自由函数或运算符。 提出的解决方案解决了手头的问题,但每个解决方案使用不同的方法 我试图找到一种方法来以相同或至少类似的方式处理每个问题。
检查类型C
是否有成员func
:
template<typename, typename T>
struct has_member {
static_assert(
std::integral_constant<T, false>::value,
"Second template parameter needs to be of function type.");
};
template<typename C, typename Ret, typename... Args>
struct has_member<C, Ret(Args...)> {
private:
template<typename T, std::enable_if_t<
std::is_same
<
decltype(std::declval<T>().func(std::declval<Args>()...)),
Ret
>::value
> * = nullptr >
static constexpr std::true_type check(T*);
template<typename>
static constexpr std::false_type check(...);
typedef decltype(check<C>(nullptr)) type;
public:
static constexpr bool value = type::value;
};
这取自这个问题最受欢迎的答案: Check if a class has a member function of a given signature 编译条件刚刚从返回类型移动到模板参数。
检查operator+
是否存在也没关系:
template<typename C, typename Ret, typename Arg>
struct has_operator {
private:
template<typename T, std::enable_if_t<
std::is_same
<
decltype(std::declval<T>() + std::declval<Arg>()),
Ret
>::value
> * = nullptr >
static constexpr std::true_type check(T*);
template<typename>
static constexpr std::false_type check(...);
typedef decltype(check<C>(nullptr)) type;
public:
static constexpr bool value = type::value;
};
检查是否存在自由函数free_func
但不起作用:
template<typename T>
struct has_function {
static_assert(
std::integral_constant<T, false>::value,
"Second template parameter needs to be of function type.");
};
template<typename Ret, typename... Args>
struct has_function<Ret(Args...)> {
private:
template<std::enable_if_t
<
std::is_same
<
decltype(free_func(std::declval<Args>()...)),
Ret
>::value
> * = nullptr >
static constexpr std::true_type check(nullptr_t);
template<typename = void>
static constexpr std::false_type check(...);
typedef decltype(check<>(nullptr)) type;
public:
static constexpr bool value = type::value;
};
使用以下声明:
struct MyStruct{
int func(double);
MyStruct operator+(const MyStruct &);
};
int free_func(double);
我得到了这些结果:
std::cout << has_member<MyStruct, int(double)>::value << std::endl; // true
std::cout << has_member<MyStruct, int(double, double)>::value << std::endl; // false
std::cout << has_function<int(double)>::value << std::endl; // true
//std::cout << has_function<int(double, double)>::value << std::endl; // compile error: free_func does not take 2 arguments
std::cout << has_operator<MyStruct, MyStruct, MyStruct>::value << std::endl; // true
std::cout << has_operator<int, int, int>::value << std::endl; // true
std::cout << has_operator<std::vector<int>, std::vector<int>, std::vector<int>>::value << std::endl; // false
我现在的问题是:在尝试检查具有给定名称和签名的自由函数是否存在时,我做错了什么?
如果我删除check(Ret*)
的第一个声明,则另一个模板会被实例化并正确评估为false
。
我假设我犯了一些错误,因此SFINAE不适用于此。
我还尝试向check
添加另一个模板参数,但不会改变结果。
template<typename T, std::enable_if_t
<
std::is_same
<
decltype(free_func(std::declval<Args>()...)),
Ret
>::value
> * = nullptr >
static constexpr std::true_type check(T *);
template<typename>
static constexpr std::false_type check(...);
typedef decltype(check<Ret>(nullptr)) type;
我想继续使用decltype(declval(...))
样式,因为它允许编译器确定是否存在任何可调用的内容,而且我不必关心函数是否通过值,引用或const获取其参数参考
感谢任何帮助。非常感谢你提前。
我一直在想的另一件事: 当我删除
has_member
和has_function
的基本模板(仅包含static_assert
)时,has_member
始终评估为false,has_function
不再编译,抱怨free_func
不接受0参数。 我假设在使用函数签名语法时,模板参数未正确绑定到Ret
和Args
,但我并不完全理解它。 所以这里的任何解释也将受到赞赏。
答案 0 :(得分:4)
我现在的问题是:在尝试检查具有给定名称和签名的自由函数是否存在时,我做错了什么?
首先 - 你不是在这里检查签名。您正在检查给定特定参数列表的调用表达式是否产生特定结果:
struct X {
int func(int);
};
static_assert(has_member<X, int(char)>::value, "!"); // doesn't fire
也就是说,检查成员函数和检查自由函数之间存在很大差异,这就是替换的直接上下文中的模板参数。在成员函数的情况下,T
是一个函数模板参数,我们尝试将其替换为此表达式:
template<typename T, std::enable_if_t<
// ~~~~~~~~~~
std::is_same
<
decltype(std::declval<T>().func(std::declval<Args>()...)),
// ~~~~~~~~~~~~~~~~~
Ret
>::value
> * = nullptr >
static constexpr std::true_type check(T*);
在自由函数的情况下,没有函数模板参数:
template<std::enable_if_t
<
std::is_same
<
decltype(free_func(std::declval<Args>()...)),
Ret
>::value
> * = nullptr >
static constexpr std::true_type check(nullptr_t);
这整个表达式可以在实例化时立即替换。它不依赖依赖 check()
中的任何参数,只来自has_function
的参数。由于free_func
不能用两个double
调用,因此该替换失败 - 但它不是在替换那些本地参数的直接上下文中,所以这是一个很难的错误。您需要更改它以确保您替换的内容与您正在检查的表达式相关。也就是说,Args...
:
template<typename Ret, typename... Args>
struct has_function<Ret(Args...)> {
private:
template<typename... A, std::enable_if_t
// ~~~~~~~~~~~~~
<
std::is_same
<
decltype(free_func(std::declval<A>()...)),
// ~~~~~~~~~~~~~~~~~
Ret
>::value
> * = nullptr >
static constexpr std::true_type check(nullptr_t);
template<typename...>
// ~~~~~~~~~~~
static constexpr std::false_type check(...);
typedef decltype(check<Args...>(nullptr)) type;
// ~~~~~~~~~~~~~~
public:
static constexpr bool value = type::value;
};
另请注意,为了使此类与非类类型一起用作参数,free_func
必须在has_function
的定义范围内。