[英]C++ SFINAE operator/function result type check
I am writing a template-based class for Polynomials. 我正在为多项式编写基于模板的类。 (Evaluation, some operations between Polynomials, differentiation, ...), like this:
template <typename _ty> class Polynomial{...
(求值,多项式之间的一些运算,微分,...),如下所示:
template <typename _ty> class Polynomial{...
For the to_string
function (and the std::ostream
-left-shift-override), I had to check, if _ty
supports the <
-operator (ie yes for real numbers, no for complex numbers), so that the string could be formatted nicely. 对于
to_string
函数(和std::ostream
-left-shift-override),我不得不检查_ty
支持<
-operator(即,对于实数为yes,对于复数为no),以便该字符串可以为格式很好。 For this I use this code: 为此,我使用以下代码:
#include <type_traits>
template <class _op, class... _ty, typename = decltype(std::declval<_op>()(std::declval<_ty>()...))>
std::true_type impl_test(const _op&, const _ty&...) { return std::true_type(); }
std::false_type impl_test(...) { return std::false_type(); }
template <class> struct supports;
template <class _op, class... _ty> struct supports<_op(_ty...)> : decltype(impl_test(std::declval<_op>(), std::declval<_ty>()...)){};
#define is_ineq_supported(type) supports<std::less<>(type, type)>()
In short, is_ineq_supported(type)
returns an std::true_type
if there is a valid overload for the <
-operator, and a false_type
if not. 简而言之,如果
<
std::true_type
有有效的重载,则is_ineq_supported(type)
返回std::true_type
否则返回false_type
。 The corresponding functions can then be called with a true_type
or false_type
as the distinguishing argument, like this: 然后可以使用
true_type
或false_type
作为区别参数来调用相应的函数,如下所示:
template <typename _ty> void do_stuff(_ty arg, const std::true_type&) {
// do stuff with the '<'-operator
}
template <typename _ty> void do_stuff(_ty arg, const std::false_type&) {
// do stuff without the '<'-operator
}
template <typename _ty> void do_stuff(_ty arg) {
do_stuff(arg, is_ineq_supported(_ty));
}
I also have a Vector class, that overloads the binary *
-operator with the dot product, so it returns a double
. 我也有一个Vector类,它用点积重载了二进制
*
-operator,因此它返回double
。 But for a polynomial, it only makes sense, to have coefficients and arguments, which return the same type when multiplied with one another. 但是对于一个多项式来说,只有系数和自变量相乘时才返回相同的类型,这才有意义。
My problem is the following: I'd like to have a way of checking, if the given operation returns a specified type.
我的问题如下:如果给定的操作返回指定的类型,我想有一种检查方法。 (maybe a similar macro?) I think, the simplest would be something that returns a
true_type
if the result type matches the argument type and a false_type
otherwise. (也许是类似的宏?)我认为,如果结果类型与参数类型匹配,则最简单的方法将返回
true_type
否则返回false_type
。 Of course, more general solutions are even better. 当然,更一般的解决方案甚至更好。
In case, the IDE and Compiler matter: I'm using Visual Studio 2015 with default settings. 万一IDE和编译器很重要:我在使用Visual Studio 2015(默认设置)。
Here is a generic, cross-platform solution using fit::is_callable
, which will be eventually added to Boost. 这是一个使用
fit::is_callable
的通用跨平台解决方案,它将最终添加到Boost中。 Also keep your eye out for std::is_callable
in C++17. 另外,请注意C ++ 17中的
std::is_callable
。
No macros necessary: 不需要宏:
#include <type_traits>
#include <iostream>
#include <fit/is_callable.hpp>
// std::less doesn't SFINAE, so we make our own test
struct less_test {
template<typename L, typename R>
auto operator()(L l, R r) -> decltype(l < r);
};
template<typename T>
using is_less_than_comparable = fit::is_callable<less_test, T, T>;
// operator< version (replace with your implementation)
template <typename T> constexpr auto
do_stuff(T arg, const std::true_type&) {
return std::integral_constant<int, 0>{};
}
// other version (replace with your implementation)
template <typename T> constexpr auto
do_stuff(T arg, const std::false_type&) {
return std::integral_constant<int, 1>{};
}
template <typename T> constexpr auto
do_stuff(T arg) {
return do_stuff(arg, is_less_than_comparable<T>{});
}
struct foo {};
int main() {
//is not less-than comparable
static_assert(do_stuff(foo{}) == 1, "");
//is less-than comparable
static_assert(do_stuff(0) == 0, "");
}
You should probably reconsider your member method detectors and use the most C++11-ish void_t
based solution. 您可能应该重新考虑成员方法检测器,并使用大多数基于C ++ 11的
void_t
解决方案。
That said, if I had to update your solution, probably the following code is a viable approach: 就是说,如果我必须更新您的解决方案,则以下代码可能是一种可行的方法:
template <class _op, class _ret, class... _ty>
typename std::enable_if<std::is_same<decltype(std::declval<_op>()(std::declval<_ty>()...)), _ret>::value, std::true_type>::type
impl_test(const _op&, const _ty&...) {
return std::true_type();
}
This will work as it follows: 这将如下工作:
struct S { int operator()() { return 42; } };
int main() {
assert((impl_test<S, int>(S{})));
// this will give you an error at compile time
// assert((impl_test<S, double>(S{})));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.